From 7b4fd28ef1fee91e9bf960db2b2a0f7bfd03aa51 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 3 Jun 2014 09:26:47 -0700 Subject: [PATCH] Ensure `_.merge` ignores `undefined` values of `source` object properties. [closes #573] --- lodash.js | 23 +++++++++++------------ test/test.js | 34 ++++++++++++++++------------------ 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/lodash.js b/lodash.js index d7e3780ba..e8b142ddd 100644 --- a/lodash.js +++ b/lodash.js @@ -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; diff --git a/test/test.js b/test/test.js index 3fc3df133..4679f5368 100644 --- a/test/test.js +++ b/test/test.js @@ -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() {