Update vendor/underscore and add _.indexBy perf and unit tests.

Former-commit-id: 5fc6c853773385aa39d470429899a35f9f17cad8
This commit is contained in:
John-David Dalton
2013-07-26 09:21:47 -07:00
parent cf26447f7c
commit 611304e257
4 changed files with 163 additions and 21 deletions

View File

@@ -287,10 +287,17 @@
};\ };\
\ \
var _boundNormal = _.bind(func, thisArg),\ var _boundNormal = _.bind(func, thisArg),\
_boundMultiple = = _boundNormal,\
_boundPartial = _.bind(func, thisArg, "hi");\ _boundPartial = _.bind(func, thisArg, "hi");\
\ \
var lodashBoundNormal = lodash.bind(func, thisArg),\ var lodashBoundNormal = lodash.bind(func, thisArg),\
lodashBoundMultiple = lodashBoundNormal,\
lodashBoundPartial = lodash.bind(func, thisArg, "hi");\ lodashBoundPartial = lodash.bind(func, thisArg, "hi");\
\
for (index = 0; index < 10; index++) {\
_boundMultiple = _.bind(_boundMultiple, { "name": "moe" + index });\
lodashBoundMultiple = lodash.bind(lodashBoundMultiple, { "name": "moe" + index });\
}\
}\ }\
\ \
if (typeof bindAll != "undefined") {\ if (typeof bindAll != "undefined") {\
@@ -643,6 +650,18 @@
}) })
); );
suites.push(
Benchmark.Suite('bound multiple times')
.add(buildName, {
'fn': 'lodashBoundMultiple()',
'teardown': 'function bind(){}'
})
.add(otherName, {
'fn': '_boundMultiple()',
'teardown': 'function bind(){}'
})
);
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push( suites.push(
@@ -1066,6 +1085,42 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('`_.indexBy` with `callback` iterating an array')
.add(buildName, '\
lodash.indexBy(numbers, function(num) { return num >> 1; })'
)
.add(otherName, '\
_.indexBy(numbers, function(num) { return num >> 1; })'
)
);
suites.push(
Benchmark.Suite('`_.indexBy` with `property` name iterating an array')
.add(buildName, {
'fn': 'lodash.indexBy(words, "length")',
'teardown': 'function countBy(){}'
})
.add(otherName, {
'fn': '_.indexBy(words, "length")',
'teardown': 'function countBy(){}'
})
);
suites.push(
Benchmark.Suite('`_.indexBy` with `callback` iterating an object')
.add(buildName, {
'fn': 'lodash.indexBy(wordToNumber, function(num) { return num >> 1; })',
'teardown': 'function countBy(){}'
})
.add(otherName, {
'fn': '_.indexBy(wordToNumber, function(num) { return num >> 1; })',
'teardown': 'function countBy(){}'
})
);
/*--------------------------------------------------------------------------*/
suites.push( suites.push(
Benchmark.Suite('`_.indexOf`') Benchmark.Suite('`_.indexOf`')
.add(buildName, { .add(buildName, {

View File

@@ -581,13 +581,40 @@
QUnit.module('lodash.countBy'); QUnit.module('lodash.countBy');
(function() { (function() {
test('should support the `thisArg` argument', function() {
var actual = _.countBy([4.2, 6.1, 6.4], function(num) {
return this.floor(num);
}, Math);
deepEqual(actual, { '4': 1, '6': 2 });
});
test('should only add values to own, not inherited, properties', function() { test('should only add values to own, not inherited, properties', function() {
var actual = _.countBy([4.2, 6.1, 6.4], function(num) { var actual = _.countBy([4.2, 6.1, 6.4], function(num) {
return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor'; return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
}); });
strictEqual(actual.constructor, 1); deepEqual(actual.constructor, 1);
equal(actual.hasOwnProperty, 2); deepEqual(actual.hasOwnProperty, 2);
});
test('should work with an object for `collection`', function() {
var actual = _.countBy({ 'a': 4.2, 'b': 6.1, 'c': 6.4 }, function(num) {
return Math.floor(num);
});
deepEqual(actual, { '4': 1, '6': 2 });
});
test('should work with a number for `callback`', function() {
var array = [
[1, 'a'],
[2, 'a'],
[2, 'b']
];
deepEqual(_.countBy(array, 0), { '1': 1, '2': 2 });
deepEqual(_.countBy(array, 1), { 'a': 2, 'b': 1 });
}); });
}()); }());
@@ -1436,6 +1463,48 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
QUnit.module('lodash.indexBy');
(function() {
test('should support the `thisArg` argument', function() {
var actual = _.indexBy([4.2, 6.1, 6.4], function(num) {
return this.floor(num);
}, Math);
deepEqual(actual, { '4': 4.2, '6': 6.4 });
});
test('should only add values to own, not inherited, properties', function() {
var actual = _.indexBy([4.2, 6.1, 6.4], function(num) {
return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
});
deepEqual(actual.constructor, 4.2);
deepEqual(actual.hasOwnProperty, 6.4);
});
test('should work with an object for `collection`', function() {
var actual = _.indexBy({ 'a': 4.2, 'b': 6.1, 'c': 6.4 }, function(num) {
return Math.floor(num);
});
deepEqual(actual, { '4': 4.2, '6': 6.4 });
});
test('should work with a number for `callback`', function() {
var array = [
[1, 'a'],
[2, 'a'],
[2, 'b']
];
deepEqual(_.indexBy(array, 0), { '1': [1 , 'a'], '2': [2, 'b'] });
deepEqual(_.indexBy(array, 1), { 'a': [2, 'a'], 'b': [2, 'b'] });
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.has'); QUnit.module('lodash.has');
(function() { (function() {

File diff suppressed because one or more lines are too long

View File

@@ -8,7 +8,7 @@
// Baseline setup // Baseline setup
// -------------- // --------------
// Establish the root object, `window` in the browser, or `global` on the server. // Establish the root object, `window` in the browser, or `exports` on the server.
var root = this; var root = this;
// Save the previous value of the `_` variable. // Save the previous value of the `_` variable.
@@ -78,7 +78,7 @@
if (nativeForEach && obj.forEach === nativeForEach) { if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context); obj.forEach(iterator, context);
} else if (obj.length === +obj.length) { } else if (obj.length === +obj.length) {
for (var i = 0, l = obj.length; i < l; i++) { for (var i = 0, length = obj.length; i < length; i++) {
if (iterator.call(context, obj[i], i, obj) === breaker) return; if (iterator.call(context, obj[i], i, obj) === breaker) return;
} }
} else { } else {
@@ -341,6 +341,14 @@
}); });
}; };
// Indexes the object's values by a criterion, similar to `groupBy`, but for
// when you know that your index values will be unique.
_.indexBy = function(obj, value, context) {
return group(obj, value, context, function(result, key, value) {
result[key] = value;
});
};
// Counts instances of an object that group by a certain criterion. Pass // Counts instances of an object that group by a certain criterion. Pass
// either a string attribute to count by, or a function that returns the // either a string attribute to count by, or a function that returns the
// criterion. // criterion.
@@ -508,7 +516,7 @@
_.object = function(list, values) { _.object = function(list, values) {
if (list == null) return {}; if (list == null) return {};
var result = {}; var result = {};
for (var i = 0, l = list.length; i < l; i++) { for (var i = 0, length = list.length; i < length; i++) {
if (values) { if (values) {
result[list[i]] = values[i]; result[list[i]] = values[i];
} else { } else {
@@ -526,17 +534,17 @@
// for **isSorted** to use binary search. // for **isSorted** to use binary search.
_.indexOf = function(array, item, isSorted) { _.indexOf = function(array, item, isSorted) {
if (array == null) return -1; if (array == null) return -1;
var i = 0, l = array.length; var i = 0, length = array.length;
if (isSorted) { if (isSorted) {
if (typeof isSorted == 'number') { if (typeof isSorted == 'number') {
i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted); i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
} else { } else {
i = _.sortedIndex(array, item); i = _.sortedIndex(array, item);
return array[i] === item ? i : -1; return array[i] === item ? i : -1;
} }
} }
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
for (; i < l; i++) if (array[i] === item) return i; for (; i < length; i++) if (array[i] === item) return i;
return -1; return -1;
}; };
@@ -562,11 +570,11 @@
} }
step = arguments[2] || 1; step = arguments[2] || 1;
var len = Math.max(Math.ceil((stop - start) / step), 0); var length = Math.max(Math.ceil((stop - start) / step), 0);
var idx = 0; var idx = 0;
var range = new Array(len); var range = new Array(length);
while(idx < len) { while(idx < length) {
range[idx++] = start; range[idx++] = start;
start += step; start += step;
} }
@@ -754,22 +762,33 @@
// Retrieve the values of an object's properties. // Retrieve the values of an object's properties.
_.values = function(obj) { _.values = function(obj) {
var values = []; var keys = _.keys(obj);
for (var key in obj) if (_.has(obj, key)) values.push(obj[key]); var length = keys.length;
var values = new Array(length);
for (var i = 0; i < length; i++) {
values[i] = obj[keys[i]];
}
return values; return values;
}; };
// Convert an object into a list of `[key, value]` pairs. // Convert an object into a list of `[key, value]` pairs.
_.pairs = function(obj) { _.pairs = function(obj) {
var pairs = []; var keys = _.keys(obj);
for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]); var length = keys.length;
var pairs = new Array(length);
for (var i = 0; i < length; i++) {
pairs[i] = [keys[i], obj[keys[i]]];
}
return pairs; return pairs;
}; };
// Invert the keys and values of an object. The values must be serializable. // Invert the keys and values of an object. The values must be serializable.
_.invert = function(obj) { _.invert = function(obj) {
var result = {}; var result = {};
for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key; var keys = _.keys(obj);
for (var i = 0, length = keys.length; i < length; i++) {
result[obj[keys[i]]] = keys[i];
}
return result; return result;
}; };
@@ -1053,8 +1072,7 @@
'<': '&lt;', '<': '&lt;',
'>': '&gt;', '>': '&gt;',
'"': '&quot;', '"': '&quot;',
"'": '&#x27;', "'": '&#x27;'
'/': '&#x2F;'
} }
}; };
entityMap.unescape = _.invert(entityMap.escape); entityMap.unescape = _.invert(entityMap.escape);
@@ -1085,7 +1103,7 @@
// Add your own custom functions to the Underscore object. // Add your own custom functions to the Underscore object.
_.mixin = function(obj) { _.mixin = function(obj) {
each(_.functions(obj), function(name){ each(_.functions(obj), function(name) {
var func = _[name] = obj[name]; var func = _[name] = obj[name];
_.prototype[name] = function() { _.prototype[name] = function() {
var args = [this._wrapped]; var args = [this._wrapped];