diff --git a/lodash.js b/lodash.js index 39e6223b3..b0aea215f 100644 --- a/lodash.js +++ b/lodash.js @@ -2313,7 +2313,8 @@ srcValue = source[key]; while (length--) { - if (stackA[length] == srcValue) { + var stacked = stackA[length]; + if (stacked == srcValue || stacked == oldValue) { assignMergeValue(object, key, stackB[length]); return; } @@ -4073,15 +4074,12 @@ * @returns {*} Returns the value to assign to the destination object. */ function mergeDefaults(objectValue, sourceValue, key, object, source, stackA, stackB) { - if (objectValue === undefined) { - return sourceValue; - } if (isObject(objectValue)) { stackA.push(objectValue); stackB.push(objectValue); - return baseMerge(objectValue, sourceValue, mergeDefaults, stackA, stackB); + baseMerge(objectValue, sourceValue, mergeDefaults, stackA, stackB); } - return objectValue; + return objectValue === undefined ? sourceValue : objectValue; } /** diff --git a/test/test.js b/test/test.js index a8237a40d..7c688293a 100644 --- a/test/test.js +++ b/test/test.js @@ -3023,6 +3023,26 @@ strictEqual(actual.a.b, 2); }); + + test('should merge sources containing circular references', 1, function() { + var object = { + 'foo': { 'b': { 'c': { 'd': {} } } }, + 'bar': { 'a': 2 } + }; + + var source = { + 'foo': { 'b': { 'c': { 'd': {} } } }, + 'bar': {} + }; + + object.foo.b.c.d = object; + source.foo.b.c.d = source; + source.bar.b = source.foo.b; + + var actual = _.defaultsDeep(object, source); + console.log(actual.bar.b === actual.foo.b , actual.foo.b.c.d === actual.foo.b.c.d.foo.b.c.d); + ok(actual.bar.b === source.foo.b && actual.foo.b.c.d === actual.foo.b.c.d.foo.b.c.d); + }); }()); /*--------------------------------------------------------------------------*/