diff --git a/lodash.js b/lodash.js index 2d42bfc06..f71ccdba2 100644 --- a/lodash.js +++ b/lodash.js @@ -2489,9 +2489,10 @@ * @param {boolean} [isDeep] Specify a deep flatten. * @param {boolean} [isStrict] Restrict flattening to arrays-like objects. * @param {Array} [result=[]] The initial result value. + * @param {Object} [stack] Tracks traversed arrays. * @returns {Array} Returns the new flattened array. */ - function baseFlatten(array, isDeep, isStrict, result) { + function baseFlatten(array, isDeep, isStrict, result, stack) { result || (result = []); var index = -1, @@ -2502,9 +2503,18 @@ if (isArrayLikeObject(value) && (isStrict || isArray(value) || isArguments(value))) { if (isDeep) { + stack || (stack = new Stack); + if (stack.get(array)) { + return result; + } + stack.set(array, true); + // Recursively flatten arrays (susceptible to call stack limits). - baseFlatten(value, isDeep, isStrict, result); - } else { + baseFlatten(value, isDeep, isStrict, result, stack); + + stack['delete'](array); + } + else { arrayPush(result, value); } } else if (!isStrict) { diff --git a/test/test.js b/test/test.js index 591d35654..d07c9aa28 100644 --- a/test/test.js +++ b/test/test.js @@ -5081,6 +5081,32 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.flattenDeep'); + + (function() { + QUnit.test('should flatten arrays with circular references', function(assert) { + assert.expect(2); + + var array = [1, 2]; + array.push(array); + + var expected = [1, 2, 1, 2]; + + try { + var actual = _.flattenDeep(array); + } catch (e) {} + + assert.deepEqual(actual, expected); + + array = [1, 2]; + array = [array, [array]]; + + assert.deepEqual(_.flattenDeep(array), expected); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('flatten methods'); (function() {