From fa2058ec7740f98a1fe3dbaeb91e9e1d8c8fe084 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 27 Dec 2014 19:42:10 -0600 Subject: [PATCH] Ensure `_.assign` and `_.merge` don't assign the `customizer` result if it is the same as the destination value. --- lodash.js | 18 +++++++++++++----- test/test.js | 26 ++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/lodash.js b/lodash.js index 6ddb1cf4a..823357d7d 100644 --- a/lodash.js +++ b/lodash.js @@ -1691,9 +1691,15 @@ while (++index < length) { var key = props[index]; - object[key] = customizer - ? customizer(object[key], source[key], key, object, source) - : source[key]; + if (customizer) { + var value = object[key], + result = customizer(value, source[key], key, object, source); + } else { + result = source[key]; + } + if (!(customizer && result === value)) { + object[key] = result; + } } return object; } @@ -2487,7 +2493,7 @@ if (typeof result == 'undefined') { result = srcValue; } - if (isSrcArr || typeof result != 'undefined') { + if ((isSrcArr || typeof result != 'undefined') && !(customizer && result === value)) { object[key] = result; } return; @@ -2520,7 +2526,9 @@ if (isDeep) { baseMerge(result, srcValue, customizer, stackA, stackB); } - object[key] = result; + if (!(customizer && result === value)) { + object[key] = result; + } }); return object; } diff --git a/test/test.js b/test/test.js index 2b60845c0..2a2348ed5 100644 --- a/test/test.js +++ b/test/test.js @@ -3576,10 +3576,10 @@ var func = _[methodName]; test('`_.' + methodName + '` should ' + (isStrict ? '' : 'not ') + 'throw strict mode errors', 1, function() { - var object = { 'a': null, 'b': function() {} }, - pass = !isStrict; - if (freeze) { + var object = { 'a': null, 'b': function() {} }, + pass = !isStrict; + freeze(object); try { if (methodName == 'bindAll') { @@ -4771,7 +4771,7 @@ deepEqual(argsList, expected, 'non-primitive property values'); }); - test('`_.' + methodName + '`should support the `thisArg` argument', 1, function() { + test('`_.' + methodName + '` should support the `thisArg` argument', 1, function() { var actual = func({}, { 'a': 0 }, function(a, b) { return this[b]; }, [2]); @@ -4789,6 +4789,24 @@ actual = func({ 'a': 1 }, callback, { 'c': 3 }); deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); }); + + test('`_.' + methodName + '` should not assign the `customizer` result if it is the same as the destination value', 1, function() { + if (defineProperty) { + var object = {}, + pass = true; + + defineProperty(object, 'a', { + 'get': _.constant({}), + 'set': function() { pass = false; } + }); + + func(object, { 'a': object.a }, _.identity); + ok(pass); + } + else { + skipTest(); + } + }); }); /*--------------------------------------------------------------------------*/