Comparing version 0.2.2 to 0.3.0
{ | ||
"name": "lodash", | ||
"version": "0.2.2", | ||
"version": "0.3.0", | ||
"description": "A drop-in replacement for Underscore.js that delivers performance improvements, bug fixes, and additional features.", | ||
@@ -5,0 +5,0 @@ "homepage": "http://lodash.com", |
301
perf/perf.js
@@ -28,2 +28,7 @@ (function(window) { | ||
/** Used to access the Firebug Lite panel */ | ||
var fbPanel = (fbPanel = window.document && document.getElementById('FirebugUI')) && | ||
(fbPanel = (fbPanel = fbPanel.contentWindow || fbPanel.contentDocument).document || fbPanel) && | ||
fbPanel.getElementById('fbPanel1'); | ||
/** Used to score Lo-Dash and Underscore performance */ | ||
@@ -45,2 +50,18 @@ var score = { 'lodash': 0, 'underscore': 0 }; | ||
/** | ||
* Logs text to the console. | ||
* | ||
* @private | ||
* @param {String} text The text to log. | ||
*/ | ||
function log(text) { | ||
console.log(text); | ||
if (fbPanel) { | ||
// scroll the Firebug Lite panel down | ||
fbPanel.scrollTop = fbPanel.scrollHeight; | ||
} | ||
} | ||
/*--------------------------------------------------------------------------*/ | ||
lodash.extend(Benchmark.options, { | ||
@@ -53,12 +74,8 @@ 'async': true, | ||
var numbers = [], | ||
var length = 20, | ||
numbers = [], | ||
object = {}, | ||
fourNumbers = [5, 25, 10, 30], | ||
nestedNumbers = [1, [2], [3, [[4]]]], | ||
twoNumbers = [12, 21], | ||
words = [ | ||
'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', | ||
'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', | ||
'seventeen', 'eighteen', 'nineteen', 'twenty' | ||
]; | ||
twoNumbers = [12, 21]; | ||
@@ -76,3 +93,33 @@ var ctor = function() { }, | ||
for (var index = 0; index < 20; index++) { | ||
var wordToNumber = { | ||
'one': 1, | ||
'two': 2, | ||
'three': 3, | ||
'four': 4, | ||
'five': 5, | ||
'six': 6, | ||
'seven': 7, | ||
'eight': 8, | ||
'nine': 9, | ||
'ten': 10, | ||
'eleven': 11, | ||
'twelve': 12, | ||
'thirteen': 13, | ||
'fourteen': 14, | ||
'fifteen': 15, | ||
'sixteen': 16, | ||
'seventeen': 17, | ||
'eighteen': 18, | ||
'nineteen': 19, | ||
'twenty': 20, | ||
'twenty-one': 21, | ||
'twenty-two': 22, | ||
'twenty-three': 23, | ||
'twenty-four': 24, | ||
'twenty-five': 25 | ||
}; | ||
var words = _.keys(wordToNumber).slice(0, length); | ||
for (var index = 0; index < length; index++) { | ||
numbers[index] = index; | ||
@@ -82,4 +129,4 @@ object['key' + index] = index; | ||
var objects = lodash.map(numbers, function(n) { | ||
return { 'num': n }; | ||
var objects = lodash.map(numbers, function(num) { | ||
return { 'num': num }; | ||
}); | ||
@@ -91,9 +138,10 @@ } | ||
'onStart': function() { | ||
console.log('\n' + this.name + ':'); | ||
log('\n' + this.name + ':'); | ||
}, | ||
'onCycle': function(event) { | ||
console.log(event.target + ''); | ||
log(event.target + ''); | ||
}, | ||
'onComplete': function() { | ||
var fastest = this.filter('fastest'), | ||
var formatNumber = Benchmark.formatNumber, | ||
fastest = this.filter('fastest'), | ||
slowest = this.filter('slowest'), | ||
@@ -104,3 +152,3 @@ lodashHz = 1 / (this[0].stats.mean + this[0].stats.moe), | ||
if (fastest.length > 1) { | ||
console.log('It\'s too close to call.'); | ||
log('It\'s too close to call.'); | ||
lodashHz = underscoreHz = Math.min(lodashHz, underscoreHz); | ||
@@ -111,5 +159,5 @@ } | ||
slowestHz = slowest[0] == this[0] ? lodashHz : underscoreHz, | ||
percent = Math.round(((fastestHz / slowestHz) - 1) * 100); | ||
percent = formatNumber(Math.round(((fastestHz / slowestHz) - 1) * 100)); | ||
console.log(fastest[0].name + ' is ' + percent + '% faster.'); | ||
log(fastest[0].name + ' is ' + percent + '% faster.'); | ||
} | ||
@@ -130,11 +178,11 @@ // add score adjusted for margin of error | ||
slowestTotalHz = Math.min(score.lodash, score.underscore), | ||
totalPercent = Math.round(((fastestTotalHz / slowestTotalHz) - 1) * 100), | ||
totalX = (fastestTotalHz / slowestTotalHz).toFixed(2), | ||
message = ' is ' + totalPercent + '% (' + totalX + 'x) faster than '; | ||
totalPercent = formatNumber(Math.round(((fastestTotalHz / slowestTotalHz) - 1) * 100)), | ||
totalX = fastestTotalHz / slowestTotalHz, | ||
message = ' is ' + totalPercent + '% ' + (totalX == 1 ? '' : '(' + formatNumber(totalX.toFixed(2)) + 'x) ') + 'faster than '; | ||
// report results | ||
if (score.lodash >= score.underscore) { | ||
console.log('\nLo-Dash' + message + 'Underscore.'); | ||
log('\nLo-Dash' + message + 'Underscore.'); | ||
} else { | ||
console.log('\nUnderscore' + message + 'Lo-Dash.'); | ||
log('\nUnderscore' + message + 'Lo-Dash.'); | ||
} | ||
@@ -158,3 +206,3 @@ } | ||
suites.push( | ||
Benchmark.Suite('bound normal') | ||
Benchmark.Suite('bound') | ||
.add('Lo-Dash', function() { | ||
@@ -193,12 +241,8 @@ lodashBoundNormal(); | ||
.add('Lo-Dash', function() { | ||
var timesTwo = []; | ||
lodash.each(numbers, function(num) { | ||
timesTwo.push(num * 2); | ||
}); | ||
var result = []; | ||
lodash.each(numbers, function(num) { result.push(num * 2); }); | ||
}) | ||
.add('Underscore', function() { | ||
var timesTwo = []; | ||
_.each(numbers, function(num) { | ||
timesTwo.push(num * 2); | ||
}); | ||
var result = []; | ||
_.each(numbers, function(num) { result.push(num * 2); }); | ||
}) | ||
@@ -208,13 +252,29 @@ ); | ||
suites.push( | ||
Benchmark.Suite('each array thisArg') | ||
.add('Lo-Dash', function() { | ||
var result = []; | ||
lodash.each(numbers, function(num, index) { | ||
result.push(num + this['key' + index]); | ||
}, object); | ||
}) | ||
.add('Underscore', function() { | ||
var result = []; | ||
_.each(numbers, function(num, index) { | ||
result.push(num + this['key' + index]); | ||
}, object); | ||
}) | ||
); | ||
suites.push( | ||
Benchmark.Suite('each object') | ||
.add('Lo-Dash', function() { | ||
var timesTwo = []; | ||
var result = []; | ||
lodash.each(object, function(num) { | ||
timesTwo.push(num * 2); | ||
result.push(num * 2); | ||
}); | ||
}) | ||
.add('Underscore', function() { | ||
var timesTwo = []; | ||
var result = []; | ||
_.each(object, function(num) { | ||
timesTwo.push(num * 2); | ||
result.push(num * 2); | ||
}); | ||
@@ -279,6 +339,6 @@ }) | ||
.add('Lo-Dash', function() { | ||
lodash.groupBy(numbers, function(num) { return Math.floor(num); }); | ||
lodash.groupBy(numbers, function(num) { return num >> 1; }); | ||
}) | ||
.add('Underscore', function() { | ||
_.groupBy(numbers, function(num) { return Math.floor(num); }); | ||
_.groupBy(numbers, function(num) { return num >> 1; }); | ||
}) | ||
@@ -300,2 +360,24 @@ ); | ||
suites.push( | ||
Benchmark.Suite('indexOf') | ||
.add('Lo-Dash', function() { | ||
lodash.indexOf(numbers, 9); | ||
}) | ||
.add('Underscore', function() { | ||
_.indexOf(numbers, 9); | ||
}) | ||
); | ||
suites.push( | ||
Benchmark.Suite('indexOf isSorted') | ||
.add('Lo-Dash', function() { | ||
lodash.indexOf(numbers, 19, true); | ||
}) | ||
.add('Underscore', function() { | ||
_.indexOf(numbers, 19, true); | ||
}) | ||
); | ||
/*--------------------------------------------------------------------------*/ | ||
suites.push( | ||
Benchmark.Suite('intersection') | ||
@@ -325,11 +407,23 @@ .add('Lo-Dash', function() { | ||
suites.push( | ||
Benchmark.Suite('lastIndexOf') | ||
.add('Lo-Dash', function() { | ||
lodash.lastIndexOf(numbers, 9); | ||
}) | ||
.add('Underscore', function() { | ||
_.lastIndexOf(numbers, 9); | ||
}) | ||
); | ||
/*--------------------------------------------------------------------------*/ | ||
suites.push( | ||
Benchmark.Suite('map') | ||
.add('Lo-Dash', function() { | ||
lodash.map(objects, function(obj) { | ||
return obj.num; | ||
lodash.map(objects, function(value) { | ||
return value.num; | ||
}); | ||
}) | ||
.add('Underscore', function() { | ||
_.map(objects, function(obj) { | ||
return obj.num; | ||
_.map(objects, function(value) { | ||
return value.num; | ||
}); | ||
@@ -339,2 +433,16 @@ }) | ||
suites.push( | ||
Benchmark.Suite('map thisArg') | ||
.add('Lo-Dash', function() { | ||
lodash.map(objects, function(value, index) { | ||
return this['key' + index] + value.num; | ||
}, object); | ||
}) | ||
.add('Underscore', function() { | ||
_.map(objects, function(value, index) { | ||
return this['key' + index] + value.num; | ||
}, object); | ||
}) | ||
); | ||
/*--------------------------------------------------------------------------*/ | ||
@@ -391,2 +499,86 @@ | ||
suites.push( | ||
Benchmark.Suite('sortBy callback') | ||
.add('Lo-Dash', function() { | ||
lodash.sortBy(numbers, function(num) { return Math.sin(num); }); | ||
}) | ||
.add('Underscore', function() { | ||
_.sortBy(numbers, function(num) { return Math.sin(num); }); | ||
}) | ||
); | ||
suites.push( | ||
Benchmark.Suite('sortBy callback thisArg') | ||
.add('Lo-Dash', function() { | ||
lodash.sortBy(numbers, function(num) { return this.sin(num); }, Math); | ||
}) | ||
.add('Underscore', function() { | ||
_.sortBy(numbers, function(num) { return this.sin(num); }, Math); | ||
}) | ||
); | ||
suites.push( | ||
Benchmark.Suite('sortBy property name') | ||
.add('Lo-Dash', function() { | ||
lodash.sortBy(words, 'length'); | ||
}) | ||
.add('Underscore', function() { | ||
_.sortBy(words, 'length'); | ||
}) | ||
); | ||
/*--------------------------------------------------------------------------*/ | ||
suites.push( | ||
Benchmark.Suite('sortedIndex') | ||
.add('Lo-Dash', function() { | ||
lodash.sortedIndex(numbers, 25); | ||
}) | ||
.add('Underscore', function() { | ||
_.sortedIndex(numbers, 25); | ||
}) | ||
); | ||
suites.push( | ||
Benchmark.Suite('sortedIndex callback') | ||
.add('Lo-Dash', function() { | ||
lodash.sortedIndex(words, 'twenty-five', function(value) { | ||
return wordToNumber[value]; | ||
}); | ||
}) | ||
.add('Underscore', function() { | ||
_.sortedIndex(words, 'twenty-five', function(value) { | ||
return wordToNumber[value]; | ||
}); | ||
}) | ||
); | ||
/*--------------------------------------------------------------------------*/ | ||
suites.push( | ||
Benchmark.Suite('times') | ||
.add('Lo-Dash', function() { | ||
var result = []; | ||
lodash.times(length, function(n) { result.push(n); }); | ||
}) | ||
.add('Underscore', function() { | ||
var result = []; | ||
_.times(length, function(n) { result.push(n); }); | ||
}) | ||
); | ||
suites.push( | ||
Benchmark.Suite('times thisArg') | ||
.add('Lo-Dash', function() { | ||
var result = []; | ||
lodash.times(length, function(n) { result.push(this.sin(n)); }, Math); | ||
}) | ||
.add('Underscore', function() { | ||
var result = []; | ||
_.times(length, function(n) { result.push(this.sin(n)); }, Math); | ||
}) | ||
); | ||
/*--------------------------------------------------------------------------*/ | ||
suites.push( | ||
Benchmark.Suite('union') | ||
@@ -404,2 +596,28 @@ .add('Lo-Dash', function() { | ||
suites.push( | ||
Benchmark.Suite('uniq') | ||
.add('Lo-Dash', function() { | ||
lodash.uniq(numbers.concat(fourNumbers, twoNumbers)); | ||
}) | ||
.add('Underscore', function() { | ||
_.uniq(numbers.concat(fourNumbers, twoNumbers)); | ||
}) | ||
); | ||
suites.push( | ||
Benchmark.Suite('uniq callback') | ||
.add('Lo-Dash', function() { | ||
lodash.uniq(numbers.concat(fourNumbers, twoNumbers), function(num) { | ||
return num % 2; | ||
}); | ||
}) | ||
.add('Underscore', function() { | ||
_.uniq(numbers.concat(fourNumbers, twoNumbers), function(num) { | ||
return num % 2; | ||
}); | ||
}) | ||
); | ||
/*--------------------------------------------------------------------------*/ | ||
suites.push( | ||
Benchmark.Suite('values') | ||
@@ -417,7 +635,8 @@ .add('Lo-Dash', function() { | ||
if (Benchmark.platform + '') { | ||
console.log(Benchmark.platform + ''); | ||
log(Benchmark.platform + ''); | ||
} | ||
// start suites | ||
log('\nSit back and relax, this may take a while.'); | ||
suites[0].run(); | ||
}(typeof global == 'object' && global || this)); |
@@ -1,7 +0,13 @@ | ||
# Lo-Dash <sup>v0.2.2</sup> | ||
# Lo-Dash <sup>v0.3.0</sup> | ||
A drop-in replacement for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), that delivers [performance improvements](http://jsperf.com/lodash-underscore#filterby=family), [bug fixes](https://github.com/bestiejs/lodash#closed-underscorejs-issues), and [additional features](https://github.com/bestiejs/lodash#features). | ||
A drop-in replacement for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), that delivers [performance improvements](http://lodash.com/benchmarks), [bug fixes](https://github.com/bestiejs/lodash#closed-underscorejs-issues), and [additional features](https://github.com/bestiejs/lodash#features). | ||
Lo-Dash’s performance is gained by avoiding slower native methods, instead opting for simplified non-ES5 compliant methods optimized for common usage, and by leveraging function compilation to reduce the number of overall function calls. | ||
## Download | ||
* [Development source](https://raw.github.com/bestiejs/lodash/v0.3.0/lodash.js) | ||
* [Production source](https://raw.github.com/bestiejs/lodash/v0.3.0/lodash.min.js) | ||
* For optimal performance, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need | ||
## Dive in | ||
@@ -22,13 +28,17 @@ | ||
* AMD loader support | ||
* AMD loader support (RequireJS, curl.js, etc.) | ||
* [_.bind](http://lodash.com/docs#bind) supports *"lazy"* binding | ||
* [_.debounce](http://lodash.com/docs#debounce)’ed functions match [_.throttle](http://lodash.com/docs#throttle)’ed functions’ return value behavior | ||
* [_.forEach](http://lodash.com/docs#forEach) is chainable | ||
* [_.groupBy](http://lodash.com/docs#groupBy) accepts a third, `thisArg`, argument | ||
* [_.forIn](http://lodash.com/docs#forIn) for iterating over an object’s own and inherited properties | ||
* [_.forOwn](http://lodash.com/docs#forOwn) for iterating over an object’s own properties | ||
* [_.groupBy](http://lodash.com/docs#groupBy), [_.sortedIndex](http://lodash.com/docs#sortedIndex), and [_.uniq](http://lodash.com/docs#uniq) accept a `thisArg` argument | ||
* [_.indexOf](http://lodash.com/docs#indexOf) and [_.lastIndexOf](http://lodash.com/docs#lastIndexOf) accept a `fromIndex` argument | ||
* [_.partial](http://lodash.com/docs#partial) for more functional fun | ||
* [_.size](http://lodash.com/docs#size) supports returning the `length` of string values | ||
* [_.template](http://lodash.com/docs#template) utilizes [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) for easier debugging | ||
## Support | ||
Lo-Dash has been tested in at least Chrome 5-19, Firefox 1.5-12, IE 6-9, Opera 9.25-11.64, Safari 3.0.4-5.1.3, Node.js 0.4.8-0.6.18, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC3. | ||
Lo-Dash has been tested in at least Chrome 5-19, Firefox 1.5-13, IE 6-9, Opera 9.25-11.64, Safari 3.0.4-5.1.3, Node.js 0.4.8-0.6.18, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC3. | ||
@@ -46,18 +56,26 @@ ## Custom builds | ||
Custom builds may be created in two ways: | ||
Custom builds may be created in three ways: | ||
1. Use the`include` argument to pass the names of the methods to include in the build. | ||
1. Use the `category` argument to pass the categories of methods to include in the build.<br> | ||
Valid categories are *"arrays"*, *"chaining"*, *"collections"*, *"functions"*, *"objects"*, and *"utilities"*. | ||
~~~ bash | ||
node build include=each,filter,map,noConflict | ||
node build include="each, filter, map, noConflict" | ||
node build mobile include=each,filter,map,noConflict | ||
node build category=collections,functions | ||
node build category="collections, functions" | ||
node build mobile category=collections,functions | ||
~~~ | ||
2. Use the `exclude` argument to pass the names of the methods to exclude from the build. | ||
2. Use the `include` argument to pass the names of the methods to include in the build. | ||
~~~ bash | ||
node build exclude=isNaN,isUndefined,union,zip | ||
node build exclude="isNaN, isUndefined, union, zip" | ||
node build mobile exclude=isNaN,isUndefined,union,zip | ||
node build include=each,filter,map | ||
node build include="each, filter, map" | ||
node build mobile include=each,filter,map | ||
~~~ | ||
3. Use the `exclude` argument to pass the names of the methods to exclude from the build. | ||
~~~ bash | ||
node build exclude=union,uniq,zip | ||
node build exclude="union, uniq, zip" | ||
node build mobile exclude=union,uniq,zip | ||
~~~ | ||
Custom builds are saved to `lodash.custom.js` and `lodash.custom.min.js`. | ||
@@ -129,13 +147,16 @@ | ||
* Ensure `_(...)` returns passed wrapper instances [[test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L95-98)] | ||
* Ensure `_.groupBy` adds values to own, not inherited, properties [[test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L229-236)] | ||
* Ensure `_.throttle` works when called in tight loops [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L436-446)] | ||
* Fix Firefox, IE, Opera, and Safari object iteration bugs [[#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L152-172), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L206-213), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L255-257), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L265-267), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L285-292), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L386-388)] | ||
* Allow iteration of objects with a `length` property [[#148](https://github.com/documentcloud/underscore/issues/148), [#154](https://github.com/documentcloud/underscore/issues/154), [#252](https://github.com/documentcloud/underscore/issues/252), [#448](https://github.com/documentcloud/underscore/issues/448), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L266-272)] | ||
* Ensure array-like objects with invalid `length` properties are treated like regular objects [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L237-243), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L533-542), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L661-664)] | ||
* Ensure `_(...)` returns passed wrapper instances [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L106-109)] | ||
* Ensure `_.groupBy` adds values to own, not inherited, properties [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L317-324)] | ||
* Ensure `_.sortedIndex` supports arrays with high `length` values [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L586-595)] | ||
* Ensure `_.throttle` works when called in tight loops [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L629-639)] | ||
* Fix Firefox, IE, Opera, and Safari object iteration bugs [[#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L175-187), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L277-302), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L379-390), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L398-400), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L418-438), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L554-556)] | ||
* Handle arrays with `undefined` values correctly in IE < 9 [[#601](https://github.com/documentcloud/underscore/issues/601)] | ||
* Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L77-83)] | ||
* Register as AMD module, but still export to global [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L61-75)] | ||
* `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/5bcd444084c92b1753feeaf66c20323e57a2dac3/test/test.js#L74-77)] | ||
* `_isNaN(new Number(NaN))` should return `true` [[test](https://github.com/bestiejs/lodash/blob/5bcd444084c92b1753feeaf66c20323e57a2dac3/test/test.js#L95-99)] | ||
* `_.reduceRight` should pass correct callback arguments when iterating objects [[test](https://github.com/bestiejs/lodash/blob/5bcd444084c92b1753feeaf66c20323e57a2dac3/test/test.js#L106-116)] | ||
* `_.size` should return the `length` of string values [[test](https://github.com/bestiejs/lodash/blob/5bcd444084c92b1753feeaf66c20323e57a2dac3/test/test.js#L121-127)] | ||
* Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L88-94)] | ||
* Register as AMD module, but still export to global [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L72-86)] | ||
* `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L232-235)] | ||
* `_isNaN(new Number(NaN))` should return `true` [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L408-410)] | ||
* `_.reduceRight` should pass correct callback arguments when iterating objects [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L521-531)] | ||
* `_.size` should return the `length` of string values [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L550-552)] | ||
@@ -188,2 +209,3 @@ ## Optimized methods <sup>(50+)</sup> | ||
* `_.throttle` | ||
* `_.times` | ||
* `_.toArray` | ||
@@ -200,5 +222,17 @@ * `_.union` | ||
### <sup>v0.3.0</sup> | ||
* Added `category` build option | ||
* Added `fromIndex` argument to `_.indexOf` and `_.lastIndexOf` | ||
* Added `//@ sourceURL` support to `_.template` | ||
* Added `thisArg` argument to `_.sortedIndex` and `_.uniq` | ||
* Added `_.forIn` and `_.forOwn` methods | ||
* Ensured array-like objects with invalid `length` properties are treated like regular objects | ||
* Ensured `_.sortedIndex` supports arrays with high `length` values | ||
* Fixed `prototype` property iteration bug in `_.keys` for Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1 | ||
* Optimized `_.times` and `this` bindings in iterator methods | ||
### <sup>v0.2.2</sup> | ||
* Added mobile build option | ||
* Added `mobile` build option | ||
* Ensured `_.find` returns `undefined` for unmatched values | ||
@@ -231,3 +265,3 @@ * Ensured `_.templateSettings.variable` is compatible with Underscore.js | ||
* Ensured `_.throttle` works in tight loops | ||
* Fixed IE < 9 `[DontEnum]` bug and Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1’s prototype property iteration bug | ||
* Fixed IE < 9 `[DontEnum]` bug and Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1’s `prototype` property iteration bug | ||
* Inlined `_.isFunction` calls. | ||
@@ -234,0 +268,0 @@ * Made `_.debounce`’ed functions match `_.throttle`’ed functions’ return value behavior |
248
test/test.js
@@ -40,2 +40,13 @@ (function(window, undefined) { | ||
/** Used to check problem JScript properties too */ | ||
var shadowedKeys = [ | ||
'constructor', | ||
'hasOwnProperty', | ||
'isPrototypeOf', | ||
'propertyIsEnumerable', | ||
'toLocaleString', | ||
'toString', | ||
'valueOf' | ||
]; | ||
/*--------------------------------------------------------------------------*/ | ||
@@ -146,2 +157,6 @@ | ||
}); | ||
test('should not escape the "/" character', function() { | ||
equal(_.escape('/'), '/'); | ||
}); | ||
}()); | ||
@@ -182,3 +197,3 @@ | ||
(function() { | ||
var array = [1, 2, 3, 4]; | ||
var array = [1, 2, 3]; | ||
@@ -190,3 +205,3 @@ test('should return found `value`', function() { | ||
test('should return `undefined` if `value` is not found', function() { | ||
equal(_.find(array, function(n) { return n == 5; }), undefined); | ||
equal(_.find(array, function(n) { return n == 4; }), undefined); | ||
}); | ||
@@ -222,13 +237,12 @@ }()); | ||
test('returns the collection', function() { | ||
var collection = [1, 2, 3, 4]; | ||
var collection = [1, 2, 3]; | ||
equal(_.forEach(collection, Boolean), collection); | ||
}); | ||
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() { | ||
var object = {}; | ||
_.forEach(shadowed, function(value, key) { | ||
object[key] = value; | ||
}); | ||
test('should treat array-like object with invalid `length` as a regular object', function() { | ||
var keys = [], | ||
object = { 'length': -1 }; | ||
deepEqual(object, shadowed); | ||
_.forEach(object, function(value, key) { keys.push(key); }); | ||
deepEqual(keys, ['length']); | ||
}); | ||
@@ -239,2 +253,60 @@ }()); | ||
QUnit.module('lodash.forIn'); | ||
(function() { | ||
test('iterates over inherited properties', function() { | ||
function Dog(name) { this.name = name; } | ||
Dog.prototype.bark = function() { /* Woof, woof! */ }; | ||
var keys = []; | ||
_.forIn(new Dog('Dagny'), function(value, key) { keys.push(key); }); | ||
deepEqual(keys.sort(), ['bark', 'name']); | ||
}); | ||
}()); | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('lodash.forOwn'); | ||
(function() { | ||
test('iterates over the `length` property', function() { | ||
var keys = [], | ||
object = { '0': 'zero', '1': 'one', 'length': 2 }; | ||
_.forOwn(object, function(value, key) { keys.push(key); }); | ||
deepEqual(keys.sort(), ['0', '1', 'length']); | ||
}); | ||
}()); | ||
/*--------------------------------------------------------------------------*/ | ||
_.each(['forEach', 'forIn', 'forOwn'], function(methodName) { | ||
var func = _[methodName]; | ||
QUnit.module('lodash.' + methodName + ' iteration bugs'); | ||
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() { | ||
var keys = []; | ||
func(shadowed, function(value, key) { keys.push(key); }); | ||
deepEqual(keys.sort(), shadowedKeys); | ||
}); | ||
test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() { | ||
function Foo() {} | ||
Foo.prototype.a = 1; | ||
var keys = []; | ||
function callback(value, key) { keys.push(key); } | ||
func(Foo, callback); | ||
deepEqual(keys, []); | ||
keys.length = 0; | ||
Foo.prototype = { 'a': 1 }; | ||
func(Foo, callback); | ||
deepEqual(keys, []); | ||
}); | ||
}); | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('lodash.groupBy'); | ||
@@ -263,2 +335,38 @@ | ||
QUnit.module('lodash.indexOf'); | ||
(function() { | ||
var array = [1, 2, 3, 1, 2, 3]; | ||
test('should work with a positive `fromIndex`', function() { | ||
equal(_.indexOf(array, 1, 2), 3); | ||
}); | ||
test('should work with `fromIndex` >= `array.length`', function() { | ||
equal(_.indexOf(array, 1, 6), -1); | ||
equal(_.indexOf(array, undefined, 6), -1); | ||
equal(_.indexOf(array, 1, 8), -1); | ||
equal(_.indexOf(array, undefined, 8), -1); | ||
}); | ||
test('should work with a negative `fromIndex`', function() { | ||
equal(_.indexOf(array, 2, -3), 4); | ||
}); | ||
test('should work with a negative `fromIndex` <= `-array.length`', function() { | ||
equal(_.indexOf(array, 1, -6), 0); | ||
equal(_.indexOf(array, 2, -8), 1); | ||
}); | ||
test('should ignore non-number `fromIndex` values', function() { | ||
equal(_.indexOf([1, 2, 3], 1, '1'), 0); | ||
}); | ||
test('should work with `isSorted`', function() { | ||
equal(_.indexOf([1, 2, 3], 1, true), 0); | ||
}); | ||
}()); | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('lodash.initial'); | ||
@@ -268,3 +376,3 @@ | ||
test('returns an empty collection for `n` of `0`', function() { | ||
var array = [1, 2, 3, 4]; | ||
var array = [1, 2, 3]; | ||
deepEqual(_.initial(array, 0), []); | ||
@@ -282,2 +390,11 @@ }); | ||
}); | ||
test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() { | ||
function Foo() {} | ||
Foo.prototype.a = 1; | ||
equal(_.isEmpty(Foo), true); | ||
Foo.prototype = { 'a': 1 }; | ||
equal(_.isEmpty(Foo), true); | ||
}); | ||
}()); | ||
@@ -315,5 +432,18 @@ | ||
deepEqual(_.keys(Foo.prototype), ['a']); | ||
deepEqual(_.keys(shadowed).sort(), | ||
'constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf'.split(' ')); | ||
deepEqual(_.keys(shadowed).sort(), shadowedKeys); | ||
}); | ||
test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() { | ||
function Foo() {} | ||
Foo.prototype.c = 3; | ||
Foo.a = 1; | ||
Foo.b = 2; | ||
var expected = ['a', 'b']; | ||
deepEqual(_.keys(Foo), expected); | ||
Foo.prototype = { 'c': 3 }; | ||
deepEqual(_.keys(Foo), expected); | ||
}); | ||
}()); | ||
@@ -323,2 +453,35 @@ | ||
QUnit.module('lodash.lastIndexOf'); | ||
(function() { | ||
var array = [1, 2, 3, 1, 2, 3]; | ||
test('should work with a positive `fromIndex`', function() { | ||
equal(_.lastIndexOf(array, 1, 2), 0); | ||
}); | ||
test('should work with `fromIndex` >= `array.length`', function() { | ||
equal(_.lastIndexOf(array, undefined, 6), -1); | ||
equal(_.lastIndexOf(array, 1, 6), 3); | ||
equal(_.lastIndexOf(array, undefined, 8), -1); | ||
equal(_.lastIndexOf(array, 1, 8), 3); | ||
}); | ||
test('should work with a negative `fromIndex`', function() { | ||
equal(_.lastIndexOf(array, 2, -3), 1); | ||
}); | ||
test('should work with a negative `fromIndex` <= `-array.length`', function() { | ||
equal(_.lastIndexOf(array, 1, -6), 0); | ||
equal(_.lastIndexOf(array, 2, -8), -1); | ||
}); | ||
test('should ignore non-number `fromIndex` values', function() { | ||
equal(_.lastIndexOf([1, 2, 3], 3, '1'), 2); | ||
equal(_.lastIndexOf([1, 2, 3], 3, true), 2); | ||
}); | ||
}()); | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('lodash.partial'); | ||
@@ -380,2 +543,13 @@ | ||
}); | ||
test('should treat array-like object with invalid `length` as a regular object', function() { | ||
var args, | ||
object = { 'a': 'A', 'length': -1 }; | ||
_.reduceRight(object, function() { | ||
args || (args = slice.call(arguments)); | ||
}); | ||
deepEqual(args, [-1, 'A', 'a', object]); | ||
}); | ||
}()); | ||
@@ -403,7 +577,7 @@ | ||
test('supports the `thisArg` argument', function() { | ||
var actual = _.sortBy([1, 2, 3, 4], function(num) { | ||
var actual = _.sortBy([1, 2, 3], function(num) { | ||
return this.sin(num); | ||
}, Math); | ||
deepEqual(actual, [4, 3, 1, 2]); | ||
deepEqual(actual, [3, 1, 2]); | ||
}); | ||
@@ -414,2 +588,27 @@ }()); | ||
QUnit.module('lodash.sortedIndex'); | ||
(function() { | ||
test('supports the `thisArg` argument', function() { | ||
var actual = _.sortedIndex([1, 2, 3], 4, function(num) { | ||
return this.sin(num); | ||
}, Math); | ||
equal(actual, 0); | ||
}); | ||
test('supports arrays with lengths larger than `Math.pow(2, 31) - 1`', function() { | ||
var length = Math.pow(2, 32) - 1, | ||
index = length - 1, | ||
array = Array(length), | ||
steps = 0; | ||
array[index] = index; | ||
_.sortedIndex(array, index, function() { steps++; }); | ||
equal(steps, 33); | ||
}); | ||
}()); | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('lodash.template'); | ||
@@ -470,3 +669,3 @@ | ||
test('should treat array-like-objects like arrays', function() { | ||
test('should treat array-like objects like arrays', function() { | ||
var object = { '0': 'a', '1': 'b', '2': 'c', 'length': 3 }; | ||
@@ -476,2 +675,7 @@ deepEqual(_.toArray(object), ['a', 'b', 'c']); | ||
}); | ||
test('should treat array-like object with invalid `length` as a regular object', function() { | ||
var object = { 'length': -1 }; | ||
deepEqual(_.toArray(object), [-1]); | ||
}); | ||
}(1, 2, 3)); | ||
@@ -481,2 +685,16 @@ | ||
QUnit.module('lodash.uniq'); | ||
(function() { | ||
test('supports the `thisArg` argument', function() { | ||
var actual = _.uniq([1, 2, 1.5, 3, 2.5], function(num) { | ||
return this.floor(num); | ||
}, Math); | ||
deepEqual(actual, [1, 2, 3]); | ||
}); | ||
}()); | ||
/*--------------------------------------------------------------------------*/ | ||
QUnit.module('lodash(...).shift'); | ||
@@ -483,0 +701,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
675609
14415
287
3