mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-01-31 07:17:50 +00:00
Add createAssigner, defaultsOwn, and expand the callback args of _.assign and _.merge.
This commit is contained in:
87
lodash.js
87
lodash.js
@@ -248,6 +248,22 @@
|
||||
return typeof objectValue == 'undefined' ? sourceValue : objectValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by `defaultsOwn` to customize its `_.assign` use.
|
||||
*
|
||||
* @private
|
||||
* @param {*} objectValue The destination object property value.
|
||||
* @param {*} sourceValue The source object property value.
|
||||
* @param {string} key The key associated with the object and source values.
|
||||
* @param {Object} object The destination object.
|
||||
* @returns {*} Returns the value to assign to the destination object.
|
||||
*/
|
||||
function assignDefaultsOwn(objectValue, sourceValue, key, object) {
|
||||
return (!hasOwnProperty.call(object, key) || typeof objectValue == 'undefined')
|
||||
? sourceValue
|
||||
: objectValue
|
||||
}
|
||||
|
||||
/**
|
||||
* The base implementation of `_.at` without support for strings or individual
|
||||
* key arguments.
|
||||
@@ -1814,17 +1830,17 @@
|
||||
* @param {Array} [stackB=[]] Associates values with source counterparts.
|
||||
*/
|
||||
function baseMerge(object, source, callback, stackA, stackB) {
|
||||
(isArray(source) ? arrayEach : baseForOwn)(source, function(source, key) {
|
||||
(isArray(source) ? arrayEach : baseForOwn)(source, function(srcValue, key, source) {
|
||||
var found,
|
||||
isArr,
|
||||
result = source,
|
||||
result = srcValue,
|
||||
value = object[key];
|
||||
|
||||
if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
|
||||
if (srcValue && ((isArr = isArray(srcValue)) || isPlainObject(srcValue))) {
|
||||
// avoid merging previously merged cyclic sources
|
||||
var stackLength = stackA.length;
|
||||
while (stackLength--) {
|
||||
if ((found = stackA[stackLength] == source)) {
|
||||
if ((found = stackA[stackLength] == srcValue)) {
|
||||
value = stackB[stackLength];
|
||||
break;
|
||||
}
|
||||
@@ -1832,7 +1848,7 @@
|
||||
if (!found) {
|
||||
var isShallow;
|
||||
if (callback) {
|
||||
result = callback(value, source);
|
||||
result = callback(value, srcValue, key, object, source);
|
||||
if ((isShallow = typeof result != 'undefined')) {
|
||||
value = result;
|
||||
}
|
||||
@@ -1843,20 +1859,20 @@
|
||||
: (isPlainObject(value) ? value : {});
|
||||
}
|
||||
// add `source` and associated `value` to the stack of traversed objects
|
||||
stackA.push(source);
|
||||
stackA.push(srcValue);
|
||||
stackB.push(value);
|
||||
|
||||
// recursively merge objects and arrays (susceptible to call stack limits)
|
||||
if (!isShallow) {
|
||||
baseMerge(value, source, callback, stackA, stackB);
|
||||
baseMerge(value, srcValue, callback, stackA, stackB);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (callback) {
|
||||
result = callback(value, source);
|
||||
result = callback(value, srcValue, key, object, source);
|
||||
if (typeof result == 'undefined') {
|
||||
result = source;
|
||||
result = srcValue;
|
||||
}
|
||||
}
|
||||
if (typeof result != 'undefined') {
|
||||
@@ -2059,6 +2075,27 @@
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that assigns own enumerable properties of source
|
||||
* object(s) to the destination object executing the callback to produce
|
||||
* the assigned values. The callback is invoked with five arguments;
|
||||
* (objectValue, sourceValue, key, object, source).
|
||||
*
|
||||
* @private
|
||||
* @param {Function} [callback] The function to customize assigning values.
|
||||
* @returns {Function} Returns the new assigner function.
|
||||
*/
|
||||
function createAssigner(callback) {
|
||||
return function(object) {
|
||||
if (!object) {
|
||||
return object;
|
||||
}
|
||||
var args = slice(arguments);
|
||||
args.push(callback);
|
||||
return assign.apply(null, args);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cache object to optimize linear searches of large arrays.
|
||||
*
|
||||
@@ -2203,6 +2240,17 @@
|
||||
: baseCreateWrapper(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is like `_.defaults` except that it ignores inherited
|
||||
* property values when checking if a property is `undefined`.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The destination object.
|
||||
* @param {...Object} [sources] The source objects.
|
||||
* @returns {Object} Returns the destination object.
|
||||
*/
|
||||
var defaultsOwn = createAssigner(assignDefaultsOwn);
|
||||
|
||||
/**
|
||||
* Finds the indexes of all placeholder elements in `array`.
|
||||
*
|
||||
@@ -5588,8 +5636,8 @@
|
||||
* Assigns own enumerable properties of source object(s) to the destination
|
||||
* object. Subsequent sources will overwrite property assignments of previous
|
||||
* sources. If a callback is provided it will be executed to produce the
|
||||
* assigned values. The callback is bound to `thisArg` and invoked with two
|
||||
* arguments; (objectValue, sourceValue).
|
||||
* assigned values. The callback is bound to `thisArg` and invoked with
|
||||
* five arguments; (objectValue, sourceValue, key, object, source).
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
@@ -5639,7 +5687,7 @@
|
||||
|
||||
while (++index < length) {
|
||||
var key = props[index];
|
||||
object[key] = callback ? callback(object[key], source[key]) : source[key];
|
||||
object[key] = callback ? callback(object[key], source[key], key, object, source) : source[key];
|
||||
}
|
||||
}
|
||||
return object;
|
||||
@@ -5812,14 +5860,7 @@
|
||||
* _.defaults({ 'name': 'barney' }, { 'name': 'fred', 'employer': 'slate' });
|
||||
* // => { 'name': 'barney', 'employer': 'slate' }
|
||||
*/
|
||||
function defaults(object) {
|
||||
if (!object) {
|
||||
return object;
|
||||
}
|
||||
var args = slice(arguments);
|
||||
args.push(assignDefaults);
|
||||
return assign.apply(null, args);
|
||||
}
|
||||
var defaults = createAssigner(assignDefaults);
|
||||
|
||||
/**
|
||||
* This method is like `_.findIndex` except that it returns the key of the
|
||||
@@ -6781,7 +6822,7 @@
|
||||
* provided it will be executed to produce the merged values of the destination
|
||||
* and source properties. If the callback returns `undefined` merging will
|
||||
* be handled by the method instead. The callback is bound to `thisArg` and
|
||||
* invoked with two arguments; (objectValue, sourceValue).
|
||||
* invoked with five arguments; (objectValue, sourceValue, key, object, source).
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
@@ -7505,10 +7546,10 @@
|
||||
// and Laura Doktorova's doT.js
|
||||
// https://github.com/olado/doT
|
||||
var settings = lodash.templateSettings;
|
||||
options = defaults({}, options, settings);
|
||||
options = defaultsOwn({}, options, settings);
|
||||
string = String(string == null ? '' : string);
|
||||
|
||||
var imports = defaults({}, options.imports, settings.imports),
|
||||
var imports = defaultsOwn({}, options.imports, settings.imports),
|
||||
importsKeys = keys(imports),
|
||||
importsValues = values(imports);
|
||||
|
||||
|
||||
77
test/test.js
77
test/test.js
@@ -639,24 +639,6 @@
|
||||
deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 });
|
||||
});
|
||||
|
||||
test('should pass the correct `callback` arguments', 1, function() {
|
||||
var args;
|
||||
|
||||
_.assign({ 'a': 1 }, { 'b': 2 }, function() {
|
||||
args || (args = slice.call(arguments));
|
||||
});
|
||||
|
||||
deepEqual(args, [undefined, 2]);
|
||||
});
|
||||
|
||||
test('should support the `thisArg` argument', 1, function() {
|
||||
var actual = _.assign({ 'a': 1, 'b': 2 }, { 'a': 3, 'c': 3 }, function(a, b) {
|
||||
return typeof this[a] == 'undefined' ? this[b] : this[a];
|
||||
}, { '1': 1, '2': 2, '3': 3 });
|
||||
|
||||
deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 });
|
||||
});
|
||||
|
||||
test('should be aliased', 1, function() {
|
||||
strictEqual(_.extend, _.assign);
|
||||
});
|
||||
@@ -3356,26 +3338,46 @@
|
||||
});
|
||||
|
||||
_.each(['assign', 'merge'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
var func = _[methodName],
|
||||
isMerge = methodName == 'merge';
|
||||
|
||||
test('`_.' + methodName + '` should pass the correct `callback` arguments', 2, function() {
|
||||
var args;
|
||||
test('`_.' + methodName + '` should pass the correct `callback` arguments', 3, function() {
|
||||
var args,
|
||||
object = { 'a': 1 },
|
||||
source = { 'a': 2 };
|
||||
|
||||
func({ 'a': 1 }, { 'a': 2 }, function() {
|
||||
func(object, source, function() {
|
||||
args || (args = slice.call(arguments));
|
||||
});
|
||||
|
||||
deepEqual(args, [1, 2], 'primitive property values');
|
||||
|
||||
var array = [1, 2],
|
||||
object = { 'b': 2 };
|
||||
deepEqual(args, [1, 2, 'a', object, source], 'primitive property values');
|
||||
|
||||
args = null;
|
||||
func({ 'a': array }, { 'a': object }, function() {
|
||||
object = { 'a': 1 };
|
||||
source = { 'b': 2 };
|
||||
|
||||
func(object, source, function() {
|
||||
args || (args = slice.call(arguments));
|
||||
});
|
||||
|
||||
deepEqual(args, [array, object], 'non-primitive property values');
|
||||
deepEqual(args, [undefined, 2, 'b', object, source], 'missing destination property');
|
||||
|
||||
var argsList = [],
|
||||
objectValue = [1, 2],
|
||||
sourceValue = { 'b': 2 };
|
||||
|
||||
object = { 'a': objectValue };
|
||||
source = { 'a': sourceValue };
|
||||
|
||||
func(object, source, function() {
|
||||
argsList.push(slice.call(arguments));
|
||||
});
|
||||
|
||||
var expected = [[objectValue, sourceValue, 'a', object, source]];
|
||||
if (isMerge) {
|
||||
expected.push([undefined, 2, 'b', sourceValue, sourceValue]);
|
||||
}
|
||||
deepEqual(argsList, expected, 'non-primitive property values');
|
||||
});
|
||||
|
||||
test('`_.' + methodName + '`should support the `thisArg` argument', 1, function() {
|
||||
@@ -6216,18 +6218,6 @@
|
||||
});
|
||||
deepEqual(actual, { 'a': { 'b': [0, 1, 2] } });
|
||||
});
|
||||
|
||||
test('should pass the correct values to `callback`', 1, function() {
|
||||
var argsList = [],
|
||||
array = [1, 2],
|
||||
object = { 'b': 2 };
|
||||
|
||||
_.merge({ 'a': array }, { 'a': object }, function(a, b) {
|
||||
argsList.push(slice.call(arguments));
|
||||
});
|
||||
|
||||
deepEqual(argsList, [[array, object], [undefined, 2]]);
|
||||
});
|
||||
}(1, 2, 3));
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -6987,8 +6977,11 @@
|
||||
source = { 'a': { 'b': 2, 'c': 3 } },
|
||||
expected = { 'a': { 'b': 1, 'c': 3 } };
|
||||
|
||||
var deepDefaults = _.partialRight(_.merge, _.defaults);
|
||||
deepEqual(deepDefaults(object, source), expected);
|
||||
var defaultsDeep = _.partialRight(_.merge, function deep(value, other) {
|
||||
return _.merge(value, other, deep);
|
||||
});
|
||||
|
||||
deepEqual(defaultsDeep(object, source), expected);
|
||||
});
|
||||
}());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user