8000 Add `callback` and `thisArg` arguments to `_.drop` and `_.pick`. [clo… · lodash/lodash@21010c6 · GitHub
[go: up one dir, main page]

Skip to content

Commit 21010c6

Browse files
committed
Add callback and thisArg arguments to _.drop and _.pick. [closes #62]
Former-commit-id: 990655e9e849348c287b3d994d2e2dc741f78fbf
1 parent a5a6cab commit 21010c6

File tree

2 files changed

+109
-33
lines changed

2 files changed

+109
-33
lines changed

lodash.js

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,22 @@
483483
'(hasOwnProperty.call(result, prop) ? result[prop]++ : result[prop] = 1)'
484484
};
485485

486+
/** Reusable iterator options for `drop` and `pick` */
487+
var dropIteratorOptions = {
488+
'useHas': false,
489+
'args': 'object, callback, thisArg',
490+
'init': '{}',
491+
'top':
492+
'var isFunc = typeof callback == \'function\';\n' +
493+
'if (!isFunc) {\n' +
494+
' var props = concat.apply(ArrayProto, arguments)\n' +
495+
'} else if (thisArg) {\n' +
496+
' callback = iteratorBind(callback, thisArg)\n' +
497+
'}',
498+
'inLoop':
499+
'if (isFunc ? !callback(value, index, object) : indexOf(props, index) < 0) result[index] = value'
500+
};
501+
486502
/** Reusable iterator options for `every` and `some` */
487503
var everyIteratorOptions = {
488504
'init': 'true',
@@ -1104,7 +1120,9 @@
11041120
/**
11051121
* Creates a shallow clone of `object` excluding the specified properties.
11061122
* Property names may be specified as individual arguments or as arrays of
1107-
* property names.
1123+
* property names. If `callback` is passed, it will be executed for each property
1124+
* in the `object`, dropping the properties `callback` returns truthy for. The
1125+
* `callback` is bound to `thisArg` and invoked with 3 arguments; (value, key, object).
11081126
*
11091127
* @static
11101128
* @memberOf _
@@ -1118,13 +1136,7 @@
11181136
* _.drop({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'userid');
11191137
* // => { 'name': 'moe', 'age': 40 }
11201138
*/
1121-
var drop = createIterator({
1122-
'useHas': false,
1123-
'args': 'object',
1124-
'init': '{}',
1125-
'top': 'var props = concat.apply(ArrayProto, arguments)',
1126-
'inLoop': 'if (indexOf(props, index) < 0) result[index] = value'
1127-
});
1139+
var drop = createIterator(dropIteratorOptions);
11281140

11291141
/**
11301142
* Assigns enumerable properties of the source object(s) to the `destination`
@@ -1763,38 +1775,38 @@
17631775
/**
17641776
* Creates a shallow clone of `object` composed of the specified properties.
17651777
* Property names may be specified as individual arguments or as arrays of
1766-
* property names.
1778+
* property names. If `callback` is passed, it will be executed for each property
1779+
* in the `object`, picking the properties `callback` returns truthy for. The
1780+
* `callback` is bound to `thisArg` and invoked with 3 arguments; (value, key, object).
17671781
*
17681782
* @static
17691783
* @memberOf _
17701784
* @category Objects
17711785
* @param {Object} object The source object.
1772-
* @param {Object} [prop1, prop2, ...] The properties to pick.
1786+
* @param {Function|String} [callback|prop1, prop2, ...] The properties to pick
1787+
* or the function called per iteration.
17731788
* @returns {Object} Returns an object composed of the picked properties.
17741789
* @example
17751790
*
17761791
* _.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age');
17771792
* // => { 'name': 'moe', 'age': 40 }
17781793
*/
1779-
function pick(object) {
1780-
var result = {};
1781-
if (!object) {
1782-
return result;
1783-
}
1784-
var prop,
1785-
index = 0,
1786-
props = concat.apply(ArrayProto, arguments),
1787-
length = props.length;
1788-
1789-
// start `index` at `1` to skip `object`
1790-
while (++index < length) {
1791-
prop = props[index];
1792-
if (prop in object) {
1793-
result[prop] = object[prop];
1794-
}
1795-
}
1796-
return result;
1797-
}
1794+
var pick = createIterator(dropIteratorOptions, {
1795+
'top':
1796+
'if (typeof callback != \'function\') {\n' +
1797+
' var prop,\n' +
1798+
' props = concat.apply(ArrayProto, arguments),\n' +
1799+
' length = props.length;\n' +
1800+
' for (index = 1; index < length; index++) {\n' +
1801+
' prop = props[index];\n' +
1802+
' if (prop in object) result[prop] = object[prop]\n' +
1803+
' }\n' +
1804+
'} else {\n' +
1805+
' if (thisArg) callback = iteratorBind(callback, thisArg)',
1806+
'inLoop':
1807+
'if (callback(value, index, object)) result[index] = value',
1808+
'bottom': '}'
1809+
});
17981810

17991811
/**
18001812
* Gets the size of `value` by returning `value.length` if `value` is an

test/test.js

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -336,11 +336,11 @@
336336
QUnit.module('lodash.drop');
337337

338338
(function() {
339-
var object = { 'a': 1, 'b': 2, 'c': 3 },
339+
var object = { 'a': 1, 'b': 2 },
340340
actual = { 'b': 2 };
341341

342342
test('should accept individual property names', function() {
343-
deepEqual(_.drop(object, 'a', 'c'), actual);
343+
deepEqual(_.drop(object, 'a'), actual);
344344
});
345345

346346
test('should accept an array of property names', function() {
@@ -355,7 +355,38 @@
355355
function Foo() {}
356356
Foo.prototype = object;
357357

358-
deepEqual(_.drop(new Foo, 'a', 'c'), actual);
358+
deepEqual(_.drop(new Foo, 'a'), actual);
359+
});
360+
361+
test('should work with a `callback` argument', function() {
362+
var actual = _.drop(object, function(value) {
363+
return value == 1;
364+
});
365+
366+
deepEqual(actual, { 'b': 2 });
367+
});
368+
369+
test('should pass the correct `callback` arguments', function() {
370+
var args,
371+
lastKey = _.keys(object).pop();
372+
373+
var expected = lastKey == 'b'
374+
? [1, 'a', object]
375+
: [2, 'b', object];
376+
377+
_.drop(object, function() {
378+
args || (args = slice.call(arguments));
379+
});
380+
381+
deepEqual(args, expected);
382+
});
383+
384+
test('should correct set the `this` binding', function() {
385+
var actual = _.drop(object, function(value) {
386+
return value == this.a;
387+
}, { 'a': 1 });
388+
389+
deepEqual(actual, { 'b': 2 });
359390
});
360391 }());
361392

@@ -1070,12 +1101,45 @@
10701101
QUnit.module('lodash.pick');
10711102

10721103
(function() {
1104+
var object = { 'a': 1, 'b': 2 };
1105+
10731106
test('should iterate over inherited properties', function() {
10741107
function Foo() {}
1075-
Foo.prototype = { 'a': 1, 'b': 2, 'c': 3 };
1108+
Foo.prototype = object;
10761109

10771110
deepEqual(_.pick(new Foo, 'b'), { 'b': 2 });
10781111
});
1112+
1113+
test('should work with a `callback` argument', function() {
1114+
var actual = _.pick(object, function(value) {
1115+
return value == 2;
1116+
});
1117+
1118+
deepEqual(actual, { 'b': 2 });
1119+
});
1120+
1121+
test('should pass the correct `callback` arguments', function() {
1122+
var args,
1123+
lastKey = _.keys(object).pop();
1124+
1125+
var expected = lastKey == 'b'
1126+
? [1, 'a', object]
1127+
: [2, 'b', object];
1128+
1129+
_.pick(object, function() {
1130+
args || (args = slice.call(arguments));
1131+
});
1132+
1133+
deepEqual(args, expected);
1134+
});
1135+
1136+
test('should correct set the `this` binding', function() {
1137+
var actual = _.pick(object, function(value) {
1138+
return value == this.b;
1139+
}, { 'b': 2 });
1140+
1141+
deepEqual(actual, { 'b': 2 });
1142+
});
10791143
}());
10801144

10811145
/*--------------------------------------------------------------------------*/

0 commit comments

Comments
 (0)
0