From c6de1ab56c12dac35e3a9c80d83f1805605fd740 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 6 Mar 2014 00:42:51 -0800 Subject: [PATCH] Add `_.negate`, `_.keysIn` and `_.valuesIn`. --- lodash.js | 148 ++++++++++++++++++++++++++++++++++++--------------- test/test.js | 5 +- 2 files changed, 108 insertions(+), 45 deletions(-) diff --git a/lodash.js b/lodash.js index 69d3150b3..842366270 100644 --- a/lodash.js +++ b/lodash.js @@ -4568,9 +4568,7 @@ */ function reject(collection, predicate, thisArg) { predicate = lodash.createCallback(predicate, thisArg, 3); - return filter(collection, function(value, index, collection) { - return !predicate(value, index, collection); - }); + return filter(collection, negate(predicate)); } /** @@ -5930,26 +5928,21 @@ * this.y = 0; * } * - * Shape.prototype.move = function(x, y) { - * this.x += x; - * this.y += y; - * }; + * Shape.prototype.z = 0; * * _.forInRight(new Shape, function(value, key) { * console.log(key); * }); - * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move' + * // => logs 'z', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'z' */ function forInRight(object, callback, thisArg) { - var pairs = []; - baseForIn(object, function(value, key) { - pairs.push(key, value); - }); + var props = keysIn(object), + length = props.length; - var length = pairs.length; callback = baseCreateCallback(callback, thisArg, 3); while (length--) { - if (callback(pairs[length--], pairs[length], object) === false) { + var prop = props[length]; + if (callback(object[prop], prop, object) === false) { break; } } @@ -6568,6 +6561,35 @@ return nativeKeys(object); }; + /** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to inspect. + * @returns {Array} Returns the array of property names. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * Shape.prototype.z = 0; + * + * _.keysIn(new Shape); + * // => ['x', 'y', 'z'] (property order is not guaranteed across environments) + */ + function keysIn(object) { + var result = []; + + baseForIn(object, function(value, key) { + result.push(key); + }); + return result; + } + /** * Creates an object with the same keys as `object` and values generated by * running each own enumerable property of `object` through the callback. @@ -6722,37 +6744,17 @@ * // => { 'name': 'fred' } */ function omit(object, predicate, thisArg) { - var result = {}; - - if (typeof predicate != 'function') { - var omitProps = baseFlatten(arguments, true, false, 1), - length = omitProps.length; - - while (length--) { - omitProps[length] = String(omitProps[length]); - } - var props = []; - baseForIn(object, function(value, key) { - props.push(key); - }); - - var index = -1; - props = baseDifference(props, omitProps); - length = props.length; - - while (++index < length) { - var key = props[index]; - result[key] = object[key]; - } - } else { + if (typeof predicate == 'function') { predicate = lodash.createCallback(predicate, thisArg, 3); - baseForIn(object, function(value, key, object) { - if (!predicate(value, key, object)) { - result[key] = value; - } - }); + return pick(object, negate(predicate)); } - return result; + var omitProps = baseFlatten(arguments, true, false, 1), + length = omitProps.length; + + while (length--) { + omitProps[length] = String(omitProps[length]); + } + return pick(object, baseDifference(keysIn(object), omitProps)); } /** @@ -6918,6 +6920,36 @@ return result; } + /** + * Creates an array composed of the own and inherited enumerable property + * values of `object`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to inspect. + * @returns {Array} Returns the new array of property values. + * @example + * + * function Shape(x, y) { + * this.x = x; + * this.y = y; + * } + * + * Shape.prototype.z = 0; + * + * _.valuesIn(new Shape(2, 1)); + * // => [2, 1, 0] (property order is not guaranteed across environments) + */ + function valuesIn(object) { + var result = []; + + baseForIn(object, function(value) { + result.push(value); + }); + return result; + } + /*--------------------------------------------------------------------------*/ /** @@ -7842,6 +7874,33 @@ } } + /** + * Creates a function that negates the result of `func`. The `func` function + * is executed with the `this` binding and arguments of the created function. + * + * @static + * @memberOf _ + * @category Utilities + * @param {Function} func The function to negate. + * @returns {Function} Returns the new function. + * @example + * + * function isEven(num) { + * return num % 2 == 0; + * } + * + * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); + * // => [1, 3, 5] + */ + function negate(func) { + if (!isFunction(func)) { + throw new TypeError; + } + return function() { + return !func.apply(this, arguments); + }; + } + /** * Reverts the '_' variable to its previous value and returns a reference to * the `lodash` function. @@ -8148,6 +8207,7 @@ lodash.invert = invert; lodash.invoke = invoke; lodash.keys = keys; + lodash.keysIn = keysIn; lodash.map = map; lodash.mapValues = mapValues; lodash.matches = matches; @@ -8155,6 +8215,7 @@ lodash.memoize = memoize; lodash.merge = merge; lodash.min = min; + lodash.negate = negate; lodash.omit = omit; lodash.once = once; lodash.pairs = pairs; @@ -8180,6 +8241,7 @@ lodash.union = union; lodash.uniq = uniq; lodash.values = values; + lodash.valuesIn = valuesIn; lodash.where = where; lodash.without = without; lodash.wrap = wrap; diff --git a/test/test.js b/test/test.js index 477ae8173..12a660b87 100644 --- a/test/test.js +++ b/test/test.js @@ -9264,6 +9264,7 @@ 'defer', 'delay', 'memoize', + 'negate', 'once', 'partial', 'partialRight', @@ -9274,7 +9275,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 182, function() { + test('should accept falsey arguments', 184, function() { var emptyArrays = _.map(falsey, function() { return []; }), isExposed = '_' in root, oldDash = root._; @@ -9343,7 +9344,7 @@ }); }); - test('should reject falsey arguments', 14, function() { + test('should reject falsey arguments', 15, function() { _.forEach(rejectFalsey, function(methodName) { var expected = _.map(falsey, function() { return true; }), func = _[methodName];