Add baseMergeDeep.

This commit is contained in:
John-David Dalton
2015-01-15 01:20:12 -08:00
committed by jdalton
parent e76f79cd56
commit 130fafd7c2

View File

@@ -2479,13 +2479,16 @@
* @returns {Object} Returns the destination object. * @returns {Object} Returns the destination object.
*/ */
function baseMerge(object, source, customizer, stackA, stackB) { function baseMerge(object, source, customizer, stackA, stackB) {
var isSrcArr = isArray(source) || isTypedArray(source); var isSrcArr = isLength(source.length) && (isArray(source) || isTypedArray(source));
(isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) { (isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) {
var value = object[key]; if (isObjectLike(srcValue)) {
stackA || (stackA = []);
if (!isObjectLike(srcValue)) { stackB || (stackB = []);
var result = customizer ? customizer(value, srcValue, key, object, source) : undefined, return baseMergeDeep(object, source, baseMerge, key, customizer, stackA, stackB);
}
var value = object[key],
result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
isCommon = typeof result == 'undefined'; isCommon = typeof result == 'undefined';
if (isCommon) { if (isCommon) {
@@ -2495,20 +2498,37 @@
(isCommon || (result === result ? result !== value : value === value))) { (isCommon || (result === result ? result !== value : value === value))) {
object[key] = result; object[key] = result;
} }
return; });
return object;
} }
// Avoid merging previously merged cyclic sources.
stackA || (stackA = []);
stackB || (stackB = []);
var length = stackA.length; /**
* A specialized version of `baseMerge` for arrays and objects which performs
* deep merges and tracks traversed objects enabling objects with circular
* references to be merged.
*
* @private
* @param {Object} object The destination object.
* @param {Object} source The source object.
* @param {Function} mergeFunc The function to merge values.
* @param {string} key The key of the property value to merge.
* @param {Function} [customizer] The function to customize merging properties.
* @param {Array} [stackA=[]] Tracks traversed source objects.
* @param {Array} [stackB=[]] Associates values with source counterparts.
* @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
*/
function baseMergeDeep(object, source, mergeFunc, key, customizer, stackA, stackB) {
var length = stackA.length,
srcValue = source[key];
while (length--) { while (length--) {
if (stackA[length] == srcValue) { if (stackA[length] == srcValue) {
object[key] = stackB[length]; object[key] = stackB[length];
return; return;
} }
} }
result = customizer ? customizer(value, srcValue, key, object, source) : undefined; var value = object[key],
result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
isCommon = typeof result == 'undefined'; isCommon = typeof result == 'undefined';
if (isCommon) { if (isCommon) {
@@ -2524,14 +2544,12 @@
stackA.push(srcValue); stackA.push(srcValue);
stackB.push(result); stackB.push(result);
// Recursively merge objects and arrays (susceptible to call stack limits).
if (isCommon) { if (isCommon) {
object[key] = baseMerge(result, srcValue, customizer, stackA, stackB); // Recursively merge objects and arrays (susceptible to call stack limits).
object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
} else if (result === result ? result !== value : value === value) { } else if (result === result ? result !== value : value === value) {
object[key] = result; object[key] = result;
} }
});
return object;
} }
/** /**
@@ -3034,7 +3052,10 @@
} }
var index = 0; var index = 0;
while (++index < length) { while (++index < length) {
assigner(object, arguments[index], customizer); var source = arguments[index];
if (source) {
assigner(object, source, customizer);
}
} }
return object; return object;
}; };