diff --git a/lodash.src.js b/lodash.src.js index e2f42f4c4..53ef589c2 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -1528,29 +1528,21 @@ } /** - * The base implementation of `_.at` without support for string collections - * and individual key arguments. + * The base implementation of `_.at` without support for individual path arguments. * * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {number[]|string[]} props The property names or indexes of elements to pick. + * @param {Object} object The object to iterate over. + * @param {string[]} paths The property paths of elements to pick. * @returns {Array} Returns the new array of picked elements. */ - function baseAt(collection, props) { + function baseAt(object, paths) { var index = -1, - isNil = collection == null, - isArr = !isNil && isArrayLike(collection), - length = isArr ? collection.length : 0, - propsLength = props.length, - result = Array(propsLength); + isNil = object == null, + length = paths.length, + result = Array(length); - while(++index < propsLength) { - var key = props[index]; - if (isArr) { - result[index] = isIndex(key, length) ? collection[key] : undefined; - } else { - result[index] = isNil ? undefined : collection[key]; - } + while(++index < length) { + result[index] = isNil ? undefined : get(object, paths[index]); } return result; } @@ -2419,9 +2411,13 @@ var length = array ? indexes.length : 0; while (length--) { var index = indexes[length]; - if (index != previous && isIndex(index)) { + if (index != previous) { var previous = index; - splice.call(array, index, 1); + if (isIndex(index)) { + splice.call(array, index, 1); + } else { + delete array[index]; + } } } return array; @@ -4783,8 +4779,8 @@ } /** - * Removes elements from `array` corresponding to the given indexes and returns - * an array of the removed elements. + * Removes elements from `array` corresponding to `indexes` and returns an + * array of removed elements. * * **Note:** Unlike `_.at`, this method mutates `array`. * @@ -5729,30 +5725,6 @@ /*------------------------------------------------------------------------*/ - /** - * Creates an array of elements corresponding to the given keys, or indexes, - * of `collection`. Keys may be specified as individual arguments or as arrays - * of keys. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {...(number|number[]|string|string[])} [props] The property names - * or indexes of elements to pick, specified individually or in arrays. - * @returns {Array} Returns the new array of picked elements. - * @example - * - * _.at(['a', 'b', 'c'], [0, 2]); - * // => ['a', 'c'] - * - * _.at(['barney', 'fred', 'pebbles'], 0, 2); - * // => ['barney', 'pebbles'] - */ - var at = restParam(function(collection, props) { - return baseAt(collection, baseFlatten(props)); - }); - /** * Creates an object composed of keys generated from the results of running * each element of `collection` through `iteratee`. The corresponding value @@ -8497,6 +8469,30 @@ copyObjectWith(source, keys(source), customizer, object); }); + /** + * Creates an array of values corresponding to `paths` of `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {...(string|string[])} [paths] The property paths of elements to pick, + * specified individually or in arrays. + * @returns {Array} Returns the new array of picked elements. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; + * + * _.at(object, ['a[0].b.c', 'a[1]']); + * // => [3, 4] + * + * _.at(['a', 'b', 'c'], 0, 2); + * // => ['a', 'c'] + */ + var at = restParam(function(object, paths) { + return baseAt(object, baseFlatten(paths)); + }); + /** * Creates an object that inherits from the given `prototype` object. If a * `properties` object is provided its own enumerable properties are assigned diff --git a/test/test.js b/test/test.js index dc833ac35..2ca18392e 100644 --- a/test/test.js +++ b/test/test.js @@ -1027,6 +1027,12 @@ var args = arguments, array = ['a', 'b', 'c']; + _.each(empties, function(value) { + if (value !== 0) { + array[value] = 1; + } + }); + array['1.1'] = array['-1'] = 1; test('should return the elements corresponding to the specified keys', 1, function() { @@ -1039,12 +1045,12 @@ deepEqual(actual, ['c', undefined, 'a']); }); - test('should use `undefined` for non-index keys on array-like values', 1, function() { + test('should work with non-index keys on array-like values', 1, function() { var values = _.reject(empties, function(value) { return value === 0 || _.isArray(value); }).concat(-1, 1.1); - var expected = _.map(values, _.constant(undefined)), + var expected = _.map(values, _.constant(1)), actual = _.at(array, values); deepEqual(actual, expected); @@ -1060,19 +1066,19 @@ deepEqual(actual, ['d', 'a', 'c']); }); - test('should work with a falsey `collection` argument when keys are provided', 1, function() { + test('should work with a falsey `object` argument when keys are provided', 1, function() { var expected = _.map(falsey, _.constant(Array(4))); - var actual = _.map(falsey, function(collection) { + var actual = _.map(falsey, function(object) { try { - return _.at(collection, 0, 1, 'pop', 'push'); + return _.at(object, 0, 1, 'pop', 'push'); } catch(e) {} }); deepEqual(actual, expected); }); - test('should work with an `arguments` object for `collection`', 1, function() { + test('should work with an `arguments` object for `object`', 1, function() { var actual = _.at(args, [2, 0]); deepEqual(actual, [3, 1]); }); @@ -1082,7 +1088,7 @@ deepEqual(actual, [2, 3, 4]); }); - test('should work with an object for `collection`', 1, function() { + test('should work with an object for `object`', 1, function() { var actual = _.at({ 'a': 1, 'b': 2, 'c': 3 }, ['c', 'a']); deepEqual(actual, [3, 1]); }); @@ -1099,9 +1105,9 @@ 'literal': 'abc', 'object': Object('abc') }, - function(collection, key) { - test('should work with a string ' + key + ' for `collection`', 1, function() { - deepEqual(_.at(collection, [2, 0]), ['c', 'a']); + function(object, key) { + test('should work with a string ' + key + ' for `object`', 1, function() { + deepEqual(_.at(object, [2, 0]), ['c', 'a']); }); }); }(1, 2, 3)); @@ -12342,23 +12348,6 @@ deepEqual(actual, ['c', undefined, 'a']); }); - test('should ignore non-index keys', 2, function() { - var array = ['a', 'b', 'c'], - clone = array.slice(); - - array['1.1'] = array['-1'] = 1; - - var values = _.reject(empties, function(value) { - return value === 0 || _.isArray(value); - }).concat(-1, 1.1, 'pop', 'push'); - - var expected = _.map(values, _.constant(undefined)), - actual = _.pullAt(array, values); - - deepEqual(actual, expected); - deepEqual(array, clone); - }); - test('should return an empty array when no indexes are provided', 4, function() { var array = ['a', 'b', 'c'], actual = _.pullAt(array);