diff --git a/.eslintrc b/.eslintrc index 73a97e193..b9ca7a590 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,7 +2,8 @@ "env": { "browser": true, "node": true, - "amd": true + "amd": true, + "es6": true }, "rules": { diff --git a/_arrayHelper.js b/_arrayHelper.js deleted file mode 100644 index 835b8fbfa..000000000 --- a/_arrayHelper.js +++ /dev/null @@ -1,12 +0,0 @@ -const shallowProperty = require('./_shallowProperty'); -const MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; -const getLength = shallowProperty('length'); - -// should be iterated as an array or as an object. -// Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength -// Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 -exports.getLength = getLength; -exports.isArrayLike = function(collection) { - var length = getLength(collection); - return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; -}; \ No newline at end of file diff --git a/_createIndexFinder.js b/_createIndexFinder.js deleted file mode 100644 index dd143402a..000000000 --- a/_createIndexFinder.js +++ /dev/null @@ -1,26 +0,0 @@ -const getLength = require('./_arrayHelper').getLength; - -// Generator function to create the indexOf and lastIndexOf functions. -module.exports = function(dir, predicateFind, sortedIndex) { - return function(array, item, idx) { - var i = 0, length = getLength(array); - if (typeof idx == 'number') { - if (dir > 0) { - i = idx >= 0 ? idx : Math.max(idx + length, i); - } else { - length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; - } - } else if (sortedIndex && idx && length) { - idx = sortedIndex(array, item); - return array[idx] === item ? idx : -1; - } - if (item !== item) { - idx = predicateFind(slice.call(array, i, length), _.isNaN); - return idx >= 0 ? idx + i : -1; - } - for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { - if (array[idx] === item) return idx; - } - return -1; - }; -}; \ No newline at end of file diff --git a/_shallowProperty.js b/_shallowProperty.js deleted file mode 100644 index 6b46d672e..000000000 --- a/_shallowProperty.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = function(key) { - return function(obj) { - return obj != null && key in obj ? obj[key] : void 0; - }; -}; \ No newline at end of file diff --git a/contains.js b/contains.js index 0a14f2458..2eea517c5 100644 --- a/contains.js +++ b/contains.js @@ -1,11 +1,2 @@ -const isArrayLike = require('./_arrayHelper').isArrayLike; -const values = require('./values'); -const indexOf = require('./indexOf'); - -// Determine if the array or object contains a given item (using `===`). // Aliased as `includes` and `include`. -module.exports = function(obj, item, fromIndex, guard) { - if (!isArrayLike(obj)) obj = values(obj); - if (typeof fromIndex != 'number' || guard) fromIndex = 0; - return indexOf(obj, item, fromIndex) >= 0; -}; \ No newline at end of file +module.exports = require('./includes'); \ No newline at end of file diff --git a/findIndex.js b/findIndex.js index 0161818fb..0e2b4bbd7 100644 --- a/findIndex.js +++ b/findIndex.js @@ -1,4 +1,19 @@ -const createPredicateIndexFinder = require('./_createPredicateIndexFinder'); +const cb = require('./cb'); +const getLength = require('./getLength'); + + +// Generator function to create the findIndex and findLastIndex functions +var createPredicateIndexFinder = function(dir) { + return function(array, predicate, context) { + predicate = cb(predicate, context); + var length = getLength(array); + var index = dir > 0 ? 0 : length - 1; + for (; index >= 0 && index < length; index += dir) { + if (predicate(array[index], index, array)) return index; + } + return -1; + }; +}; // Returns the first index on an array-like that passes a predicate test. module.exports = createPredicateIndexFinder(1); \ No newline at end of file diff --git a/first.js b/first.js index c11dff916..1846cfd6c 100644 --- a/first.js +++ b/first.js @@ -5,15 +5,15 @@ module.exports = function first(array, n, guard) { n = 1; } var result = []; - find(array, function(value) { + find(array, function (value) { if (result.length !== n && result.length < n) { result.push(value); } else { return true; } }); - if (result.length === 1) { + if (result.length && n === 1) { result = result.pop(); } return result; -}; \ No newline at end of file +}; diff --git a/getLength.js b/getLength.js new file mode 100644 index 000000000..cde55a731 --- /dev/null +++ b/getLength.js @@ -0,0 +1 @@ +module.exports = require('./property')('length'); \ No newline at end of file diff --git a/id.js b/id.js new file mode 100644 index 000000000..f190d7c6c --- /dev/null +++ b/id.js @@ -0,0 +1,3 @@ +module.exports = function (id) { + return id; +} \ No newline at end of file diff --git a/includes.js b/includes.js new file mode 100644 index 000000000..fc94d2905 --- /dev/null +++ b/includes.js @@ -0,0 +1,10 @@ +// Determine if the array or object contains a given item (using `===`). +// Aliased as `includes` and `include`. +const isArrayLike = require('./isArrayLike'); +const indexOf = require('./indexOf'); + +module.exports = function(obj, item, fromIndex, guard) { + if (!isArrayLike(obj)) obj = require('./values')(obj); + if (typeof fromIndex != 'number' || guard) fromIndex = 0; + return indexOf(obj, item, fromIndex) >= 0; +}; \ No newline at end of file diff --git a/indexOf.js b/indexOf.js index 9a4ac5dbb..a17f82b80 100644 --- a/indexOf.js +++ b/indexOf.js @@ -1,9 +1,68 @@ -const createIndexFinder = require('./_createIndexFinder'); -const findIndex = require('./findIndex'); -const sortedIndex = require('./sortedIndex'); +const getLength = require('./getLength'); +const cb = require('./cb'); +const isNumber = require('./isNumber'); + +const _isNaN = function(obj) { + return _.isNumber(obj) && isNaN(obj); +}; + +// Generator function to create the findIndex and findLastIndex functions +var createPredicateIndexFinder = function(dir) { + return function(array, predicate, context) { + predicate = cb(predicate, context); + var length = getLength(array); + var index = dir > 0 ? 0 : length - 1; + for (; index >= 0 && index < length; index += dir) { + if (predicate(array[index], index, array)) return index; + } + return -1; + }; +}; + + // Returns the first index on an array-like that passes a predicate test +const findIndex = createPredicateIndexFinder(1); + + + // Use a comparator function to figure out the smallest index at which + // an object should be inserted so as to maintain order. Uses binary search. +const sortedIndex = function(array, obj, iteratee, context) { + iteratee = cb(iteratee, context, 1); + var value = iteratee(obj); + var low = 0, high = getLength(array); + while (low < high) { + var mid = Math.floor((low + high) / 2); + if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; + } + return low; +}; + + // Generator function to create the indexOf and lastIndexOf functions +var createIndexFinder = function(dir, predicateFind, sortedIndex) { + return function(array, item, idx) { + var i = 0, length = getLength(array); + if (typeof idx == 'number') { + if (dir > 0) { + i = idx >= 0 ? idx : Math.max(idx + length, i); + } else { + length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; + } + } else if (sortedIndex && idx && length) { + idx = sortedIndex(array, item); + return array[idx] === item ? idx : -1; + } + if (item !== item) { + idx = predicateFind(slice.call(array, i, length), _isNaN); + return idx >= 0 ? idx + i : -1; + } + for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { + if (array[idx] === item) return idx; + } + return -1; + }; +}; // Return the position of the first occurrence of an item in an array, // or -1 if the item is not included in the array. // If the array is large and already in sort order, pass `true` // for **isSorted** to use binary search. -module.exports = createIndexFinder(1, findIndex, sortedIndex); \ No newline at end of file + module.exports = createIndexFinder(1, findIndex, sortedIndex); \ No newline at end of file diff --git a/isArrayLike.js b/isArrayLike.js new file mode 100644 index 000000000..c3c48bf25 --- /dev/null +++ b/isArrayLike.js @@ -0,0 +1,7 @@ +const getLength = require('./getLength'); +const MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; + +module.exports = function(collection) { + const length = getLength(collection); + return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; +}; \ No newline at end of file diff --git a/isBoolean.js b/isBoolean.js index 4287e8f6e..d0a1faf66 100644 --- a/isBoolean.js +++ b/isBoolean.js @@ -1,4 +1,3 @@ -// Is a given value a boolean? module.exports = function(obj) { - return obj === true || obj === false || Object.prototype.toString.call(obj) === '[object Boolean]'; + return obj === true || obj === false || Object.prototype.toString.call(obj) === '[object Boolean]'; }; \ No newline at end of file diff --git a/isNumber.js b/isNumber.js new file mode 100644 index 000000000..188b9aec1 --- /dev/null +++ b/isNumber.js @@ -0,0 +1,3 @@ +module.exports = function(obj) { + return Object.prototype.toString.call(obj) === '[object Number]'; +}; \ No newline at end of file diff --git a/range.js b/range.js index 89f3ff55f..60490e8eb 100644 --- a/range.js +++ b/range.js @@ -1,4 +1,4 @@ -module.exports = function range(start, stop, step) { +module.exports = function(start, stop, step) { if (stop == null) { stop = start || 0; start = 0; @@ -8,11 +8,11 @@ module.exports = function range(start, stop, step) { } var length = Math.max(Math.ceil((stop - start) / step), 0); - var rng = new Array(length); + var range = Array(length); for (var idx = 0; idx < length; idx++, start += step) { - rng[idx] = start; + range[idx] = start; } - return rng; + return range; }; \ No newline at end of file diff --git a/sortedIndex.js b/sortedIndex.js index 1e37f4207..ae7b69c26 100644 --- a/sortedIndex.js +++ b/sortedIndex.js @@ -1,5 +1,5 @@ const cb = require('./cb'); -const getLength = require('./_arrayHelper').getLength; +const getLength = require('./getLength'); // Use a comparator function to figure out the smallest index at which // an object should be inserted so as to maintain order. Uses binary search. diff --git a/underscore.js b/underscore.js index 25ba35037..5318d1009 100644 --- a/underscore.js +++ b/underscore.js @@ -382,26 +382,7 @@ }; // Return the maximum element (or element-based computation). - _.max = function(obj, iteratee, context) { - var result = -Infinity, lastComputed = -Infinity, computed; - if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object') && obj != null) { - _.each(obj, function(value) { - if (value > result) { - result = value; - } - }); - } else { - iteratee = cb(iteratee, context); - _.each(obj, function(v, index, list) { - computed = iteratee(v, index, list); - if (computed > lastComputed || computed === -Infinity && result === -Infinity) { - result = v; - lastComputed = computed; - } - }); - } - return result; - }; + _.max = require('./max'); // Return the minimum element (or element-based computation). _.min = function(obj, iteratee, context) { @@ -504,16 +485,16 @@ _.countBy = group(function(result, value, key) { if (_.has(result, key)) result[key]++; else result[key] = 1; }); - + var reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g; // Safely create a real, live array from anything iterable. _.toArray = function(obj) { if (!obj) return []; if (_.isArray(obj)) return slice.call(obj); if (_.isString(obj)) { - // Keep surrogate pair characters together - return obj.match(reStrSymbol); - } + // Keep surrogate pair characters together + return obj.match(reStrSymbol); + } if (isArrayLike(obj)) return _.map(obj, _.identity); return _.values(obj); }; @@ -549,7 +530,7 @@ return true; } }); - if (result.length === 1) { + if (result.length && n === 1) { result = result.pop(); } return result; @@ -783,24 +764,7 @@ // Generate an integer Array containing an arithmetic progression. A port of // the native Python `range()` function. See // [the Python documentation](http://docs.python.org/library/functions.html#range). - _.range = function(start, stop, step) { - if (stop == null) { - stop = start || 0; - start = 0; - } - if (!step) { - step = stop < start ? -1 : 1; - } - - var length = Math.max(Math.ceil((stop - start) / step), 0); - var range = Array(length); - - for (var idx = 0; idx < length; idx++, start += step) { - range[idx] = start; - } - - return range; - }; + _.range = require('./range'); // Split an **array** into several arrays containing **count** or less elements // of initial array @@ -1357,7 +1321,6 @@ } - // Is a given object a finite number? _.isFinite = function(obj) { return !_.isSymbol(obj) && isFinite(obj) && !isNaN(parseFloat(obj)); @@ -1655,4 +1618,4 @@ return '' + this._wrapped; }; -}(this)); +}(module.exports)); diff --git a/uniq.js b/uniq.js index 47aeab5bd..c239ec584 100644 --- a/uniq.js +++ b/uniq.js @@ -1,35 +1,33 @@ -const restArgs = require('./restArgs'); -const isBoolean = require('./isBoolean'); -const getLength = require('./_arrayHelper').getLength; -const cb = require('./cb'); -const contains = require('./contains'); - // Produce a duplicate-free version of the array. If the array has already // been sorted, you have the option of using a faster algorithm. -// Aliased as `unique`. -module.exports = function(array, isSorted, iteratee, context) { +const getLength = require('./getLength'); +const contains = require('./includes'); +const cb = require('./cb'); +const isBoolean = require('./isBoolean'); + +module.exports = function(array, isSorted, iteratee, context) { if (!isBoolean(isSorted)) { - context = iteratee; - iteratee = isSorted; - isSorted = false; + context = iteratee; + iteratee = isSorted; + isSorted = false; } if (iteratee != null) iteratee = cb(iteratee, context); var result = []; var seen = []; for (var i = 0, length = getLength(array); i < length; i++) { - var value = array[i], - computed = iteratee ? iteratee(value, i, array) : value; - if (isSorted) { + var value = array[i], + computed = iteratee ? iteratee(value, i, array) : value; + if (isSorted) { if (!i || seen !== computed) result.push(value); seen = computed; - } else if (iteratee) { + } else if (iteratee) { if (!contains(seen, computed)) { - seen.push(computed); - result.push(value); + seen.push(computed); + result.push(value); } - } else if (!contains(result, value)) { + } else if (!contains(result, value)) { result.push(value); - } + } } return result; }; \ No newline at end of file