diff --git a/lodash.js b/lodash.js index bd34bd114..7004408e3 100644 --- a/lodash.js +++ b/lodash.js @@ -1006,16 +1006,16 @@ * `zip`, and `zipObject` * * The non-chainable wrapper functions are: - * `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `contains`, - * `deburr`, endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, - * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, - * `has`, `identity`, `indexOf`, `isArguments`, `isArray`, `isBoolean`, isDate`, - * `isElement`, `isEmpty`, `isEqual`, `isError`, `isFinite`, `isFunction`, - * `isNative`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, - * `isRegExp`, `isString`, `isUndefined`, `join`, `kebabCase`, `last`, - * `lastIndexOf`, `max`, `min`, `noConflict`, `now`, `pad`, `padLeft`, `padRight`, - * `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, `repeat`, `result`, - * `runInContext`, `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, + * `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`, + * `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, + * `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, `has`, + * `identity`, `includes`, `indexOf`, `isArguments`, `isArray`, `isBoolean`, + * `isDate`, `isElement`, `isEmpty`, `isEqual`, `isError`, `isFinite`, + * `isFunction`, `isNative`, `isNaN`, `isNull`, `isNumber`, `isObject`, + * `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`, `kebabCase`, + * `last`, `lastIndexOf`, `max`, `min`, `noConflict`, `now`, `pad`, `padLeft`, + * `padRight`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, `repeat`, + * `result`, `runInContext`, `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, * `sortedLastIndex`, `startsWith`, `template`, `trim`, `trimLeft`, `trimRight`, * `trunc`, `unescape`, `uniqueId`, `value`, and `words` * @@ -5065,7 +5065,7 @@ * * @static * @memberOf _ - * @alias include + * @alias contains, include * @category Collection * @param {Array|Object|string} collection The collection to search. * @param {*} target The value to search for. @@ -5073,19 +5073,19 @@ * @returns {boolean} Returns `true` if a matching element is found, else `false`. * @example * - * _.contains([1, 2, 3], 1); + * _.includes([1, 2, 3], 1); * // => true * - * _.contains([1, 2, 3], 1, 2); + * _.includes([1, 2, 3], 1, 2); * // => false * - * _.contains({ 'user': 'fred', 'age': 40 }, 'fred'); + * _.includes({ 'user': 'fred', 'age': 40 }, 'fred'); * // => true * - * _.contains('pebbles', 'eb'); + * _.includes('pebbles', 'eb'); * // => true */ - function contains(collection, target, fromIndex) { + function includes(collection, target, fromIndex) { var length = collection ? collection.length : 0; if (!isLength(length)) { @@ -10012,7 +10012,6 @@ lodash.capitalize = capitalize; lodash.clone = clone; lodash.cloneDeep = cloneDeep; - lodash.contains = contains; lodash.deburr = deburr; lodash.endsWith = endsWith; lodash.escape = escape; @@ -10028,6 +10027,7 @@ lodash.first = first; lodash.has = has; lodash.identity = identity; + lodash.includes = includes; lodash.indexOf = indexOf; lodash.isArguments = isArguments; lodash.isArray = isArray; @@ -10084,11 +10084,12 @@ // Add aliases. lodash.all = every; lodash.any = some; + lodash.contains = includes; lodash.detect = find; lodash.foldl = reduce; lodash.foldr = reduceRight; lodash.head = first; - lodash.include = contains; + lodash.include = includes; lodash.inject = reduce; mixin(lodash, (function() { diff --git a/perf/perf.js b/perf/perf.js index 410feeea8..eaf726287 100644 --- a/perf/perf.js +++ b/perf/perf.js @@ -692,40 +692,6 @@ /*--------------------------------------------------------------------------*/ - suites.push( - Benchmark.Suite('`_.contains` iterating an array') - .add(buildName, '\ - lodash.contains(numbers, limit - 1)' - ) - .add(otherName, '\ - _.contains(numbers, limit - 1)' - ) - ); - - suites.push( - Benchmark.Suite('`_.contains` iterating an object') - .add(buildName, '\ - lodash.contains(object, limit - 1)' - ) - .add(otherName, '\ - _.contains(object, limit - 1)' - ) - ); - - if (lodash.contains('ab', 'ab') && _.contains('ab', 'ab')) { - suites.push( - Benchmark.Suite('`_.contains` iterating a string') - .add(buildName, '\ - lodash.contains(strNumbers, "," + (limit - 1))' - ) - .add(otherName, '\ - _.contains(strNumbers, "," + (limit - 1))' - ) - ); - } - - /*--------------------------------------------------------------------------*/ - suites.push( Benchmark.Suite('`_.countBy` with `callback` iterating an array') .add(buildName, '\ @@ -1077,6 +1043,40 @@ /*--------------------------------------------------------------------------*/ + suites.push( + Benchmark.Suite('`_.includes` iterating an array') + .add(buildName, '\ + lodash.includes(numbers, limit - 1)' + ) + .add(otherName, '\ + _.includes(numbers, limit - 1)' + ) + ); + + suites.push( + Benchmark.Suite('`_.includes` iterating an object') + .add(buildName, '\ + lodash.includes(object, limit - 1)' + ) + .add(otherName, '\ + _.includes(object, limit - 1)' + ) + ); + + if (lodash.includes('ab', 'ab') && _.includes('ab', 'ab')) { + suites.push( + Benchmark.Suite('`_.includes` iterating a string') + .add(buildName, '\ + lodash.includes(strNumbers, "," + (limit - 1))' + ) + .add(otherName, '\ + _.includes(strNumbers, "," + (limit - 1))' + ) + ); + } + + /*--------------------------------------------------------------------------*/ + suites.push( Benchmark.Suite('`_.indexBy` with `callback` iterating an array') .add(buildName, '\ diff --git a/test/index.html b/test/index.html index 9a271845b..7d824549b 100644 --- a/test/index.html +++ b/test/index.html @@ -112,9 +112,6 @@ setProperty(Number, '_isFinite', Number.isFinite); setProperty(Number, 'isFinite', noop); - setProperty(stringProto, '_contains', stringProto.contains); - setProperty(stringProto, 'contains', stringProto._contains ? noop : Boolean); - setProperty(window, '_ArrayBuffer', window.ArrayBuffer); if (window.ArrayBuffer && window.Uint8Array) { ArrayBuffer = (function(_ArrayBuffer) { @@ -220,11 +217,6 @@ } else { delete Number.isFinite; } - if (stringProto._contains) { - setProperty(stringProto, 'contains', stringProto._contains); - } else { - delete stringProto.contains; - } if (window._ArrayBuffer) { ArrayBuffer = _ArrayBuffer; } @@ -261,7 +253,6 @@ delete Object._getPrototypeOf; delete Object._keys; delete objectProto._propertyIsEnumerable; - delete stringProto._contains; } QUnit.config.hidepassed = true; diff --git a/test/test.js b/test/test.js index 72c87749a..571ee5813 100644 --- a/test/test.js +++ b/test/test.js @@ -453,9 +453,6 @@ var _isFinite = Number.isFinite; setProperty(Number, 'isFinite', _.noop); - var _contains = stringProto.contains; - setProperty(stringProto, 'contains', _contains ? _.noop : Boolean); - var _ArrayBuffer = ArrayBuffer; setProperty(root, 'ArrayBuffer', (function() { function ArrayBuffer(byteLength) { @@ -543,11 +540,6 @@ } else { delete Number.isFinite; } - if (_contains) { - setProperty(stringProto, 'contains', _contains); - } else { - delete stringProto.contains; - } if (_ArrayBuffer) { setProperty(root, 'ArrayBuffer', _ArrayBuffer); } else { @@ -685,7 +677,7 @@ } }); - test('should avoid overwritten native methods', 14, function() { + test('should avoid overwritten native methods', 13, function() { function Foo() {} function message(lodashMethod, nativeMethod) { @@ -751,13 +743,6 @@ } deepEqual(actual, [[otherObject], [object], [object]], message('_.difference`, `_.intersection`, and `_.uniq', 'Set')); - try { - actual = lodashBizarro.contains('abc', 'c'); - } catch(e) { - actual = null; - } - strictEqual(actual, true, message('_.contains', 'String#contains')); - if (ArrayBuffer) { try { var buffer = new ArrayBuffer(10); @@ -787,7 +772,7 @@ } } else { - skipTest(14); + skipTest(13); } }); }()); @@ -2032,100 +2017,6 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.contains'); - - (function() { - _.each({ - 'an `arguments` object': arguments, - 'an array': [1, 2, 3, 4], - 'an object': { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, - 'a string': '1234' - }, - function(collection, key) { - var values = _.toArray(collection); - - test('should work with ' + key + ' and return `true` for matched values', 1, function() { - strictEqual(_.contains(collection, 3), true); - }); - - test('should work with ' + key + ' and return `false` for unmatched values', 1, function() { - strictEqual(_.contains(collection, 5), false); - }); - - test('should work with ' + key + ' and a positive `fromIndex`', 2, function() { - strictEqual(_.contains(collection, values[2], 2), true); - strictEqual(_.contains(collection, values[1], 2), false); - }); - - test('should work with ' + key + ' and a `fromIndex` >= `collection.length`', 12, function() { - _.each([6, 8, Math.pow(2, 32), Infinity], function(fromIndex) { - strictEqual(_.contains(collection, 1, fromIndex), false); - strictEqual(_.contains(collection, undefined, fromIndex), false); - strictEqual(_.contains(collection, '', fromIndex), false); - }); - }); - - test('should work with ' + key + ' and treat falsey `fromIndex` values as `0`', 1, function() { - var expected = _.map(falsey, _.constant(true)); - - var actual = _.map(falsey, function(fromIndex) { - return _.contains(collection, values[0], fromIndex); - }); - - deepEqual(actual, expected); - }); - - test('should work with ' + key + ' and treat non-number `fromIndex` values as `0`', 1, function() { - strictEqual(_.contains(collection, values[0], '1'), true); - }); - - test('should work with ' + key + ' and a negative `fromIndex`', 2, function() { - strictEqual(_.contains(collection, values[2], -2), true); - strictEqual(_.contains(collection, values[1], -2), false); - }); - - test('should work with ' + key + ' and a negative `fromIndex` <= negative `collection.length`', 3, function() { - _.each([-4, -6, -Infinity], function(fromIndex) { - strictEqual(_.contains(collection, values[0], fromIndex), true); - }); - }); - - test('should work with ' + key + ' and return an unwrapped value when chaining', 1, function() { - if (!isNpm) { - strictEqual(_(collection).contains(3), true); - } - else { - skipTest(); - } - }); - }); - - _.each({ - 'literal': 'abc', - 'object': Object('abc') - }, - function(collection, key) { - test('should work with a string ' + key + ' for `collection`', 2, function() { - strictEqual(_.contains(collection, 'bc'), true); - strictEqual(_.contains(collection, 'd'), false); - }); - }); - - test('should not be possible to perform a binary search', 1, function() { - strictEqual(_.contains([3, 2, 1], 3, true), true); - }); - - test('should match `NaN`', 1, function() { - strictEqual(_.contains([1, NaN, 3], NaN), true); - }); - - test('should be aliased', 1, function() { - strictEqual(_.include, _.contains); - }); - }(1, 2, 3, 4)); - - /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.countBy'); (function() { @@ -4438,11 +4329,11 @@ args || (args = slice.call(arguments)); }); - if (_.contains(rightMethods, methodName)) { + if (_.includes(rightMethods, methodName)) { expected[0] = 3; expected[1] = 2; } - if (_.contains(objectMethods, methodName)) { + if (_.includes(objectMethods, methodName)) { expected[1] += ''; } deepEqual(args, expected); @@ -4476,7 +4367,7 @@ return isEvery; }); - ok(!_.contains(keys, 'a')); + ok(!_.includes(keys, 'a')); }); }); @@ -4527,8 +4418,8 @@ _.each(iterationMethods, function(methodName) { var array = [1, 2, 3], func = _[methodName], - isEach = !_.contains(objectMethods, methodName), - isRight = _.contains(rightMethods, methodName); + isEach = !_.includes(objectMethods, methodName), + isRight = _.includes(rightMethods, methodName); test('`_.' + methodName + '` should return the collection', 1, function() { strictEqual(func(array, Boolean), array); @@ -5003,6 +4894,101 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.includes'); + + (function() { + _.each({ + 'an `arguments` object': arguments, + 'an array': [1, 2, 3, 4], + 'an object': { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, + 'a string': '1234' + }, + function(collection, key) { + var values = _.toArray(collection); + + test('should work with ' + key + ' and return `true` for matched values', 1, function() { + strictEqual(_.includes(collection, 3), true); + }); + + test('should work with ' + key + ' and return `false` for unmatched values', 1, function() { + strictEqual(_.includes(collection, 5), false); + }); + + test('should work with ' + key + ' and a positive `fromIndex`', 2, function() { + strictEqual(_.includes(collection, values[2], 2), true); + strictEqual(_.includes(collection, values[1], 2), false); + }); + + test('should work with ' + key + ' and a `fromIndex` >= `collection.length`', 12, function() { + _.each([6, 8, Math.pow(2, 32), Infinity], function(fromIndex) { + strictEqual(_.includes(collection, 1, fromIndex), false); + strictEqual(_.includes(collection, undefined, fromIndex), false); + strictEqual(_.includes(collection, '', fromIndex), false); + }); + }); + + test('should work with ' + key + ' and treat falsey `fromIndex` values as `0`', 1, function() { + var expected = _.map(falsey, _.constant(true)); + + var actual = _.map(falsey, function(fromIndex) { + return _.includes(collection, values[0], fromIndex); + }); + + deepEqual(actual, expected); + }); + + test('should work with ' + key + ' and treat non-number `fromIndex` values as `0`', 1, function() { + strictEqual(_.includes(collection, values[0], '1'), true); + }); + + test('should work with ' + key + ' and a negative `fromIndex`', 2, function() { + strictEqual(_.includes(collection, values[2], -2), true); + strictEqual(_.includes(collection, values[1], -2), false); + }); + + test('should work with ' + key + ' and a negative `fromIndex` <= negative `collection.length`', 3, function() { + _.each([-4, -6, -Infinity], function(fromIndex) { + strictEqual(_.includes(collection, values[0], fromIndex), true); + }); + }); + + test('should work with ' + key + ' and return an unwrapped value when chaining', 1, function() { + if (!isNpm) { + strictEqual(_(collection).contains(3), true); + } + else { + skipTest(); + } + }); + }); + + _.each({ + 'literal': 'abc', + 'object': Object('abc') + }, + function(collection, key) { + test('should work with a string ' + key + ' for `collection`', 2, function() { + strictEqual(_.includes(collection, 'bc'), true); + strictEqual(_.includes(collection, 'd'), false); + }); + }); + + test('should not be possible to perform a binary search', 1, function() { + strictEqual(_.includes([3, 2, 1], 3, true), true); + }); + + test('should match `NaN`', 1, function() { + strictEqual(_.includes([1, NaN, 3], NaN), true); + }); + + test('should be aliased', 2, function() { + strictEqual(_.contains, _.includes); + strictEqual(_.include, _.includes); + }); + }(1, 2, 3, 4)); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.indexBy'); (function() { @@ -5150,11 +5136,11 @@ return new Foo; }); - test('`_.contains` should work with a custom `_.indexOf` method', 2, function() { + test('`_.includes` should work with a custom `_.indexOf` method', 2, function() { if (!isModularize) { _.indexOf = custom; - ok(_.contains(array, new Foo)); - ok(_.contains({ 'a': 1, 'b': new Foo, 'c': 3 }, new Foo)); + ok(_.includes(array, new Foo)); + ok(_.includes({ 'a': 1, 'b': new Foo, 'c': 3 }, new Foo)); _.indexOf = indexOf; } else { @@ -7259,7 +7245,7 @@ actual = func(object); delete proto.a; - strictEqual(_.contains(actual, 'a'), !(isKeys && index), 'includes ' + message); + strictEqual(_.includes(actual, 'a'), !(isKeys && index), 'includes ' + message); if (index) { object.constructor = 1; @@ -10251,12 +10237,12 @@ test('should return a random element', 1, function() { var actual = _.sample(array); - ok(_.contains(array, actual)); + ok(_.includes(array, actual)); }); test('should return two random elements', 1, function() { var actual = _.sample(array, 2); - ok(actual.length == 2 && actual[0] !== actual[1] && _.contains(array, actual[0]) && _.contains(array, actual[1])); + ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(array, actual[0]) && _.includes(array, actual[1])); }); test('should contain elements of the collection', 1, function() { @@ -10311,10 +10297,10 @@ var object = { 'a': 1, 'b': 2, 'c': 3 }, actual = _.sample(object); - ok(_.contains(array, actual)); + ok(_.includes(array, actual)); actual = _.sample(object, 2); - ok(actual.length == 2 && actual[0] !== actual[1] && _.contains(array, actual[0]) && _.contains(array, actual[1])); + ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(array, actual[0]) && _.includes(array, actual[1])); }); test('should work as an iteratee for `_.map`', 2, function() { @@ -10324,7 +10310,7 @@ c = values[2], actual = _.map(values, _.sample); - ok(_.contains(a, actual[0]) && _.contains(b, actual[1]) && _.contains(c, actual[2])); + ok(_.includes(a, actual[0]) && _.includes(b, actual[1]) && _.includes(c, actual[2])); }); }); @@ -10334,7 +10320,7 @@ ok(wrapped instanceof _); var actual = wrapped.value(); - ok(actual.length == 2 && actual[0] !== actual[1] && _.contains(array, actual[0]) && _.contains(array, actual[1])); + ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(array, actual[0]) && _.includes(array, actual[1])); } else { skipTest(2); @@ -10344,7 +10330,7 @@ test('should return an unwrapped value when chaining and `n` is not provided', 1, function() { if (!isNpm) { var actual = _(array).sample(); - ok(_.contains(array, actual)); + ok(_.includes(array, actual)); } else { skipTest(); @@ -10358,10 +10344,10 @@ function(collection, key) { test('should work with a string ' + key + ' for `collection`', 2, function() { var actual = _.sample(collection); - ok(_.contains(collection, actual)); + ok(_.includes(collection, actual)); actual = _.sample(collection, 2); - ok(actual.length == 2 && actual[0] !== actual[1] && _.contains(collection, actual[0]) && _.contains(collection, actual[1])); + ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(collection, actual[0]) && _.includes(collection, actual[1])); }); }); }()); @@ -13461,7 +13447,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 199, function() { + test('should accept falsey arguments', 200, function() { var emptyArrays = _.map(falsey, _.constant([])), isExposed = '_' in root, oldDash = root._; @@ -13489,7 +13475,7 @@ else if (methodName == 'pull') { expected = falsey; } - if (_.contains(returnArrays, methodName) && methodName != 'sample') { + if (_.includes(returnArrays, methodName) && methodName != 'sample') { deepEqual(actual, expected, '_.' + methodName + ' returns an array'); } ok(pass, '`_.' + methodName + '` accepts falsey arguments'); @@ -13606,9 +13592,9 @@ if (func) { if (/^reduce/.test(methodName) || methodName == 'transform') { func(array, callback, 0, null); - } else if (_.contains(['assign', 'merge'], methodName)) { + } else if (_.includes(['assign', 'merge'], methodName)) { func(array, array, callback, null); - } else if (_.contains(['isEqual', 'sortedIndex'], methodName)) { + } else if (_.includes(['isEqual', 'sortedIndex'], methodName)) { func(array, 'a', callback, null); } else if (methodName == 'times') { func(1, callback, null);