Ensure _.merge ignores undefined values of source object properties. [closes #573]

This commit is contained in:
John-David Dalton
2014-06-03 09:26:47 -07:00
parent b2280b2d72
commit 7b4fd28ef1
2 changed files with 27 additions and 30 deletions

View File

@@ -1962,7 +1962,8 @@
* @returns {Object} Returns the destination object.
*/
function baseMerge(object, source, callback, stackA, stackB) {
(isArrayLike(source) ? arrayEach : baseForOwn)(source, function(srcValue, key, source) {
var isSrcArr = isArrayLike(source);
(isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) {
var isArr = srcValue && isArrayLike(srcValue),
isObj = srcValue && isPlainObject(srcValue),
value = object[key];
@@ -1972,10 +1973,9 @@
if (typeof result == 'undefined') {
result = srcValue;
}
if (typeof result != 'undefined') {
value = result;
if (isSrcArr || typeof result != 'undefined') {
object[key] = result;
}
object[key] = value;
return;
}
// avoid merging previously merged cyclic sources
@@ -1992,22 +1992,21 @@
var result = callback ? callback(value, srcValue, key, object, source) : undefined,
isShallow = typeof result != 'undefined';
if (isShallow) {
value = result;
} else {
value = isArr
if (!isShallow) {
result = isArr
? (isArray(value) ? value : [])
: (isPlainObject(value) ? value : {});
}
// add `source` and associated `value` to the stack of traversed objects
// add the source value to the stack of traversed objects
// and associate it with its merged value
stackA.push(srcValue);
stackB.push(value);
stackB.push(result);
// recursively merge objects and arrays (susceptible to call stack limits)
if (!isShallow) {
baseMerge(value, srcValue, callback, stackA, stackB);
baseMerge(result, srcValue, callback, stackA, stackB);
}
object[key] = value;
object[key] = result;
});
return object;

View File

@@ -2580,22 +2580,6 @@
deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 });
});
if (methodName == 'merge') {
test('`_.' + methodName + '` should treat sparse arrays as dense', 2, function() {
var array = Array(3);
array[0] = 1;
array[2] = 3;
var actual = func([], array),
expected = array.slice();
expected[1] = undefined;
ok('1' in actual);
deepEqual(actual, expected);
});
}
});
/*--------------------------------------------------------------------------*/
@@ -6365,6 +6349,20 @@
ok(actual.bar.b === actual.foo.b && actual.foo.b.foo.c === actual.foo.b.foo.c.foo.b.foo.c);
});
test('should treat sources that are sparse arrays as dense', 2, function() {
var array = Array(3);
array[0] = 1;
array[2] = 3;
var actual = _.merge([], array),
expected = array.slice();
expected[1] = undefined;
ok('1' in actual);
deepEqual(actual, expected);
});
test('should not treat `arguments` objects as plain objects', 1, function() {
var object = {
'args': args
@@ -6389,8 +6387,8 @@
});
test('should not assign `undefined` values', 1, function() {
var actual = _.merge({ 'a': 1 }, { 'a': undefined });
strictEqual(actual.a, 1);
var actual = _.merge({ 'a': 1 }, { 'a': undefined, 'b': undefined });
deepEqual(actual, { 'a': 1 });
});
test('should handle merging if `callback` returns `undefined`', 1, function() {