diff --git a/lodash.js b/lodash.js index 01b19d757..832182d7f 100644 --- a/lodash.js +++ b/lodash.js @@ -4764,20 +4764,18 @@ } /** - * Initializes an array of property names based on `object`. If `object` is - * an array, `arguments` object, or `string` its index keys are returned, - * otherwise an empty array is returned. + * Creates an array of index keys for `object` values of arrays, + * `arguments` objects, and strings, otherwise `null` is returned. * * @private * @param {Object} object The object to query. - * @returns {Array} Returns the initialized array of property names. + * @returns {Array|null} Returns index keys, else `null`. */ - function initKeys(object) { - var length = object ? object.length : 0; - length = (length && isLength(length) && - (isArray(object) || isString(object) || isArguments(object)) && length) || 0; - - return baseTimes(length, String); + function indexKeys(object) { + var length = object ? object.length : undefined; + return (isLength(length) && (isArray(object) || isString(object) || isArguments(object))) + ? baseTimes(length, String) + : null; } /** @@ -10808,13 +10806,14 @@ if (!(isProto || isArrayLike(object))) { return baseKeys(object); } - var result = initKeys(object), - length = result.length, - skipIndexes = !!length; + var indexes = indexKeys(object), + skipIndexes = !!indexes, + result = indexes || [], + length = result.length; for (var key in object) { if (baseHas(object, key) && - !(skipIndexes && isIndex(key, length)) && + !(skipIndexes && (key == 'length' || isIndex(key, length))) && !(isProto && key == 'constructor')) { result.push(key); } @@ -10849,13 +10848,14 @@ isProto = isPrototype(object), props = baseKeysIn(object), propsLength = props.length, - result = initKeys(object), - length = result.length, - skipIndexes = !!length; + indexes = indexKeys(object), + skipIndexes = !!indexes, + result = indexes || [], + length = result.length; while (++index < propsLength) { var key = props[index]; - if (!(skipIndexes && isIndex(key, length)) && + if (!(skipIndexes && (key == 'length' || isIndex(key, length))) && !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { result.push(key); } diff --git a/test/test.js b/test/test.js index 825bb472f..511bc011b 100644 --- a/test/test.js +++ b/test/test.js @@ -10678,7 +10678,8 @@ QUnit.module('keys methods'); lodashStable.each(['keys', 'keysIn'], function(methodName) { - var args = arguments, + var args = (function() { return arguments; }(1, 2, 3)), + strictArgs = (function() { 'use strict'; return arguments; }(1, 2, 3)), func = _[methodName], isKeys = methodName == 'keys'; @@ -10740,25 +10741,43 @@ QUnit.test('`_.' + methodName + '` should work with `arguments` objects', function(assert) { assert.expect(1); - assert.deepEqual(func(args).sort(), ['0', '1', '2']); + var values = [args, strictArgs], + expected = lodashStable.map(values, lodashStable.constant(['0', '1', '2'])), + actual = lodashStable.map(values, func); + + assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should return keys for custom properties on `arguments` objects', function(assert) { assert.expect(1); - args.a = 1; - assert.deepEqual(func(args).sort(), ['0', '1', '2', 'a']); - delete args.a; + var values = [args, strictArgs], + expected = lodashStable.map(values, lodashStable.constant(['0', '1', '2', 'a'])); + + var actual = lodashStable.map(values, function(value) { + value.a = 1; + var result = func(value).sort(); + delete value.a; + return result; + }); + + assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties of `arguments` objects', function(assert) { assert.expect(1); - var expected = isKeys ? ['0', '1', '2'] : ['0', '1', '2', 'a']; + var values = [args, strictArgs], + expected = lodashStable.map(values, lodashStable.constant(isKeys ? ['0', '1', '2'] : ['0', '1', '2', 'a'])); - objectProto.a = 1; - assert.deepEqual(func(args).sort(), expected); - delete objectProto.a; + var actual = lodashStable.map(values, function(value) { + objectProto.a = 1; + var result = func(value).sort(); + delete objectProto.a; + return result; + }); + + assert.deepEqual(actual, expected); }); QUnit.test('`_.' + methodName + '` should work with string objects', function(assert) {