lodash: Cleanup source. [jddalton]

This commit is contained in:
John-David Dalton
2012-04-17 23:47:27 -04:00
parent 27f3729508
commit 37cdb762f9

308
lodash.js
View File

@@ -98,20 +98,6 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
// Helper function to continue chaining intermediate results.
function resultWrapper(collection, chain) {
return chain ? lodash(collection).chain() : collection;
}
// A method to easily add functions to the OOP wrapper.
function addToWrapper(name, func) {
Wrapper.prototype[name] = function() {
var args = slice.call(arguments);
unshift.call(args, this._wrapped);
return resultWrapper(func.apply(lodash, args), this._chain);
};
}
/** /**
* Internal recursive comparison function * Internal recursive comparison function
* *
@@ -371,7 +357,7 @@
* _.forforEach([1, 2, 3], function(num) { alert(num); }); * _.forforEach([1, 2, 3], function(num) { alert(num); });
* // => alerts each number in turn... * // => alerts each number in turn...
* *
* _.forforEach({ 'one' : 1, 'two' : 2, 'three' : 3}, function(num) { alert(num); }); * _.forforEach({ 'one': 1, 'two': 2, 'three': 3}, function(num) { alert(num); });
* // => alerts each number in turn... * // => alerts each number in turn...
*/ */
function forEach(collection, callback, thisArg) { function forEach(collection, callback, thisArg) {
@@ -474,7 +460,7 @@
* _.map([1, 2, 3], function(num) { return num * 3; }); * _.map([1, 2, 3], function(num) { return num * 3; });
* // => [3, 6, 9] * // => [3, 6, 9]
* *
* _.map({ 'one' : 1, 'two' : 2, 'three' : 3 }, function(num) { return num * 3; }); * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
* // => [3, 6, 9] * // => [3, 6, 9]
*/ */
function map(collection, callback, thisArg) { function map(collection, callback, thisArg) {
@@ -506,23 +492,31 @@
* @example * @example
* *
* var stooges = [ * var stooges = [
* { 'name' : 'moe', 'age' : 40}, * { 'name': 'moe', 'age': 40 },
* { 'name' : 'larry', 'age' : 50}, * { 'name': 'larry', 'age': 50 },
* { 'name' : 'curly', 'age' : 60} * { 'name': 'curly', 'age': 60 }
* ]; * ];
* *
* _.max(stooges, function(stooge) { return stooge.age; }); * _.max(stooges, function(stooge) { return stooge.age; });
* // => { 'name' : 'curly', 'age' : 60 }; * // => { 'name': 'curly', 'age': 60 };
*/ */
function max(collection, callback, thisArg) { function max(collection, callback, thisArg) {
if (!callback && isArray(collection) && collection[0] === +collection[0]) if (!callback) {
return Math.max.apply(Math, collection); if (isArray(collection) && collection[0] === +collection[0]) {
if (!callback && isEmpty(collection)) return Math.max.apply(Math, collection);
return -Infinity; }
var result = {computed : -Infinity}; if (isEmpty(collection)) {
return -Infinity;
}
} else if (thisArg) {
callback = bind(callback, thisArg);
}
var result = { 'computed': -Infinity };
forEach(collection, function(value, index, array) { forEach(collection, function(value, index, array) {
var computed = callback ? callback.call(thisArg, value, index, array) : value; var computed = callback ? callback(value, index, array) : value;
computed >= result.computed && (result = { 'computed': computed, 'value': value }); if (computed >= result.computed) {
result = { 'computed': computed, 'value': value };
}
}); });
return result.value; return result.value;
} }
@@ -547,12 +541,22 @@
* // => 2 * // => 2
*/ */
function min(collection, callback, thisArg) { function min(collection, callback, thisArg) {
if (!callback && isArray(collection) && collection[0] === +collection[0]) return Math.min.apply(Math, collection); if (!callback) {
if (!callback && isEmpty(collection)) return Infinity; if (isArray(collection) && collection[0] === +collection[0]) {
var result = {computed : Infinity}; return Math.min.apply(Math, collection);
}
if (isEmpty(collection)) {
return Infinity;
}
} else if (thisArg) {
callback = bind(callback, thisArg);
}
var result = { 'computed': Infinity };
forEach(collection, function(value, index, array) { forEach(collection, function(value, index, array) {
var computed = callback ? callback.call(thisArg, value, index, array) : value; var computed = callback ? callback(value, index, array) : value;
computed < result.computed && (result = { 'computed': computed, 'value': value }); if (computed < result.computed) {
result = { 'computed': computed, 'value': value };
}
}); });
return result.value; return result.value;
} }
@@ -569,16 +573,16 @@
* @example * @example
* *
* var stooges = [ * var stooges = [
* { 'name' : 'moe', 'age' : 40}, * { 'name': 'moe', 'age': 40 },
* { 'name' : 'larry', 'age' : 50}, * { 'name': 'larry', 'age': 50 },
* { 'name' : 'curly', 'age' : 60} * { 'name': 'curly', 'age': 60 }
* ]; * ];
* *
* _.pluck(stooges, 'name'); * _.pluck(stooges, 'name');
* // => ['moe', 'larry', 'curly'] * // => ['moe', 'larry', 'curly']
*/ */
function pluck(collection, key) { function pluck(collection, key) {
return map(collection, function(value){ return value[key]; }); return map(collection, function(value) { return value[key]; });
} }
/** /**
@@ -605,16 +609,17 @@
*/ */
function reduce(collection, callback, accumulator, thisArg) { function reduce(collection, callback, accumulator, thisArg) {
var initial = arguments.length > 2; var initial = arguments.length > 2;
if (collection == null) collection = []; if (thisArg) {
forEach(collection, function(value, index, array) { callback = bind(callback, thisArg);
}
forEach(collection, function(value, index) {
if (!initial) { if (!initial) {
accumulator = value; accumulator = value;
initial = true; initial = true;
} else { } else {
accumulator = callback.call(thisArg, accumulator, value, index, array); accumulator = callback(accumulator, value, index, collection);
} }
}); });
if (!initial) throw new TypeError('Reduce of empty array with no initial value');
return accumulator; return accumulator;
} }
@@ -640,10 +645,9 @@
* // => [4, 5, 2, 3, 0, 1] * // => [4, 5, 2, 3, 0, 1]
*/ */
function reduceRight(collection, callback, accumulator, thisArg) { function reduceRight(collection, callback, accumulator, thisArg) {
var initial = arguments.length > 2; var initial = arguments.length > 2,
if (collection == null) collection = []; reversed = toArray(collection).reverse();
var reversed = toArray(collection).reverse();
if (thisArg && !initial) callback = bind(callback, thisArg);
return initial ? reduce(reversed, callback, accumulator, thisArg) : reduce(reversed, callback); return initial ? reduce(reversed, callback, accumulator, thisArg) : reduce(reversed, callback);
} }
@@ -689,13 +693,15 @@
* // => [4, 1, 6, 3, 5, 2] * // => [4, 1, 6, 3, 5, 2]
*/ */
function shuffle(collection) { function shuffle(collection) {
var shuffled = [], rand; var rand,
result = [];
forEach(collection, function(value, index, array) { forEach(collection, function(value, index, array) {
rand = Math.floor(Math.random() * (index + 1)); rand = Math.floor(Math.random() * (index + 1));
shuffled[index] = shuffled[rand]; result[index] = result[rand];
shuffled[rand] = value; result[rand] = value;
}); });
return shuffled; return result;
} }
/** /**
@@ -739,16 +745,24 @@
if (!isFunction(callback)) { if (!isFunction(callback)) {
var key = callback; var key = callback;
callback = function(collection) { return collection[key]; }; callback = function(collection) { return collection[key]; };
} else if (thisArg) {
callback = bind(callback, thisArg);
} }
return pluck(map(collection, function(value, index, array) { return pluck(map(collection, function(value, index) {
return { return {
'value' : value, 'criteria': callback(value, index, collection),
'criteria' : callback.call(thisArg, value, index, array) 'value': value
}; };
}).sort(function(left, right) { }).sort(function(left, right) {
var a = left.criteria, b = right.criteria; var a = left.criteria,
if (a === void 0) return 1; b = right.criteria;
if (b === void 0) return -1;
if (a === undefined) {
return 1;
}
if (b === undefined) {
return -1;
}
return a < b ? -1 : a > b ? 1 : 0; return a < b ? -1 : a > b ? 1 : 0;
}), 'value'); }), 'value');
} }
@@ -774,8 +788,12 @@
* // => true * // => true
*/ */
function some(collection, callback, thisArg) { function some(collection, callback, thisArg) {
callback || (callback = identity);
var result = false; var result = false;
if (!callback) {
callback = identity;
} else if (thisArg) {
callback = bind(callback, thisArg);
}
if (collection == null) return result; if (collection == null) return result;
forEach(collection, function(value, index, array) { forEach(collection, function(value, index, array) {
if (result || (result = callback.call(thisArg, value, index, array))) return breaker; if (result || (result = callback.call(thisArg, value, index, array))) return breaker;
@@ -804,11 +822,13 @@
* // => 3 * // => 3
*/ */
function sortedIndex(array, object, callback) { function sortedIndex(array, object, callback) {
var low = 0,
high = array.length;
callback || (callback = identity); callback || (callback = identity);
var low = 0, high = array.length;
while (low < high) { while (low < high) {
var mid = (low + high) >> 1; var mid = (low + high) >> 1;
callback(array[mid]) < callback(object) ? low = mid + 1 : high = mid; callback(array[mid]) < callback(object) ? (low = mid + 1) : (high = mid);
} }
return low; return low;
} }
@@ -931,7 +951,7 @@
push.apply(accumulator, flatten(value)); push.apply(accumulator, flatten(value));
return accumulator; return accumulator;
} }
accumulator[accumulator.length] = value; accumulator.push(value);
return accumulator; return accumulator;
}, []); }, []);
} }
@@ -1053,10 +1073,13 @@
* // => 4 * // => 4
*/ */
function lastIndexOf(array, value) { function lastIndexOf(array, value) {
if (array != null) { if (array == null) {
var index = array.length; return -1;
while (index--) { }
if (array[index] === value) return index; var index = array.length;
while (index--) {
if (array[index] === value) {
return index;
} }
} }
return -1; return -1;
@@ -1092,17 +1115,17 @@
* // => [] * // => []
*/ */
function range(start, end, step) { function range(start, end, step) {
if (arguments.length <= 1) { step || (step = 1);
if (arguments.length < 2) {
end = start || 0; end = start || 0;
start = 0; start = 0;
} }
step = arguments[2] || 1;
var length = Math.max(Math.ceil((end - start) / step), 0); var idx = 0,
var idx = 0; length = Math.max(Math.ceil((end - start) / step), 0),
var result = new Array(length); result = Array(length);
while(idx < length) { while (idx < length) {
result[idx++] = start; result[idx++] = start;
start += step; start += step;
} }
@@ -1185,6 +1208,7 @@
} }
return accumulator; return accumulator;
}, []); }, []);
return result; return result;
} }
@@ -1224,10 +1248,11 @@
* // => [['moe', 30, true], ['larry', 40, false], ['curly', 50, false]] * // => [['moe', 30, true], ['larry', 40, false], ['curly', 50, false]]
*/ */
function zip() { function zip() {
var length = max(pluck(arguments, 'length')), var index = -1,
length = max(pluck(arguments, 'length')),
result = Array(length); result = Array(length);
for (var index = 0; index < length; index++) { while (++index < length) {
result[index] = pluck(arguments, index); result[index] = pluck(arguments, index);
} }
return result; return result;
@@ -1279,13 +1304,13 @@
* @returns {Function} Returns the new bound function. * @returns {Function} Returns the new bound function.
* @example * @example
* *
* var func = function(greeting){ return greeting + ': ' + this.name; }; * var func = function(greeting) { return greeting + ': ' + this.name; };
* func = _.bind(func, { 'name': 'moe' }, 'hi'); * func = _.bind(func, { 'name': 'moe' }, 'hi');
* func(); * func();
* // => 'hi: moe' * // => 'hi: moe'
*/ */
function bind(func, thisArg) { function bind(func, thisArg) {
var args = args = slice.call(arguments, 2), var args = slice.call(arguments, 2),
argsLength = args.length; argsLength = args.length;
return function() { return function() {
@@ -1320,8 +1345,12 @@
*/ */
function bindAll(object) { function bindAll(object) {
var funcs = slice.call(arguments, 1); var funcs = slice.call(arguments, 1);
if (funcs.length == 0) funcs = functions(object); if (!funcs.length) {
forEach(funcs, function(f) { object[f] = bind(object[f], object); }); funcs = functions(object);
}
forEach(funcs, function(methodName) {
object[methodName] = bind(object[methodName], object);
});
return object; return object;
} }
@@ -1376,14 +1405,19 @@
function debounce(func, wait, immediate) { function debounce(func, wait, immediate) {
var timeout; var timeout;
return function() { return function() {
var thisArg = this, args = arguments; var args = arguments,
var later = function() { thisArg = this;
timeout = null;
if (!immediate) func.apply(thisArg, args); if (immediate && !timeout) {
}; func.apply(thisArg, args);
if (immediate && !timeout) func.apply(thisArg, args); }
clearTimeout(timeout); clearTimeout(timeout);
timeout = setTimeout(later, wait); timeout = setTimeout(function() {
timeout = null;
if (!immediate) {
func.apply(thisArg, args);
}
}, wait);
}; };
} }
@@ -1406,7 +1440,7 @@
*/ */
function delay(func, wait) { function delay(func, wait) {
var args = slice.call(arguments, 2); var args = slice.call(arguments, 2);
return setTimeout(function(){ return func.apply(null, args); }, wait); return setTimeout(function() { return func.apply(null, args); }, wait);
} }
/** /**
@@ -1421,7 +1455,7 @@
* @returns {Number} Returns the `setTimeout` timeout id. * @returns {Number} Returns the `setTimeout` timeout id.
* @example * @example
* *
* _.defer(function(){ alert('deferred'); }); * _.defer(function() { alert('deferred'); });
* // Returns from the function before the alert runs. * // Returns from the function before the alert runs.
*/ */
function defer(func) { function defer(func) {
@@ -1453,7 +1487,9 @@
hasher || (hasher = identity); hasher || (hasher = identity);
return function() { return function() {
var key = hasher.apply(this, arguments); var key = hasher.apply(this, arguments);
return hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = func.apply(this, arguments)); return hasOwnProperty.call(cache, key)
? cache[key]
: (cache[key] = func.apply(this, arguments));
}; };
} }
@@ -1482,7 +1518,8 @@
return result; return result;
} }
ran = true; ran = true;
return (result = func.apply(this, arguments)); result = func.apply(this, arguments);
return result;
}; };
} }
@@ -1502,16 +1539,22 @@
* jQuery(window).on('scroll', throttled); * jQuery(window).on('scroll', throttled);
*/ */
function throttle(func, wait) { function throttle(func, wait) {
var thisArg, args, timeout, throttling, more, result; var args, more, result, thisArg, throttling, timeout,
var whenDone = debounce(function(){ more = throttling = false; }, wait); whenDone = debounce(function() { more = throttling = false; }, wait);
return function() { return function() {
thisArg = this; args = arguments; args = arguments;
var later = function() { thisArg = this;
timeout = null;
if (more) func.apply(thisArg, args); if (!timeout) {
whenDone(); timeout = setTimeout(function() {
}; timeout = null;
if (!timeout) timeout = setTimeout(later, wait); if (more) {
func.apply(thisArg, args);
}
whenDone();
}, wait);
}
if (throttling) { if (throttling) {
more = true; more = true;
} else { } else {
@@ -1643,7 +1686,9 @@
function functions(object) { function functions(object) {
var names = []; var names = [];
for (var key in object) { for (var key in object) {
if (isFunction(object[key])) names.push(key); if (isFunction(object[key])) {
names.push(key);
}
} }
return names.sort(); return names.sort();
} }
@@ -2008,7 +2053,7 @@
var result = []; var result = [];
for (var key in object) { for (var key in object) {
if (hasOwnProperty.call(object, key)) { if (hasOwnProperty.call(object, key)) {
result[result.length] = key; result.push(key);
} }
} }
return result; return result;
@@ -2032,7 +2077,9 @@
function pick(object) { function pick(object) {
var result = {}; var result = {};
forEach(flatten(slice.call(arguments, 1)), function(key) { forEach(flatten(slice.call(arguments, 1)), function(key) {
if (key in object) result[key] = object[key]; if (key in object) {
result[key] = object[key];
}
}); });
return result; return result;
} }
@@ -2098,7 +2145,8 @@
* // => "Curly, Larry &amp; Moe" * // => "Curly, Larry &amp; Moe"
*/ */
function escape(string) { function escape(string) {
return (string + '').replace(/&/g, '&amp;').replace(/</g, '&lt;') return (string + '')
.replace(/&/g, '&amp;').replace(/</g, '&lt;')
.replace(/>/g, '&gt;').replace(/"/g, '&quot;') .replace(/>/g, '&gt;').replace(/"/g, '&quot;')
.replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;'); .replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
} }
@@ -2145,8 +2193,20 @@
* // => 'Larry' * // => 'Larry'
*/ */
function mixin(object) { function mixin(object) {
forEach(functions(object), function(name){ forEach(functions(object), function(methodName) {
addToWrapper(name, lodash[name] = object[name]); var func = lodash[methodName] = object[methodName];
lodash.prototype[methodName] = function() {
// In Opera < 9.50 and some older/beta Mobile Safari versions using `unshift()`
// generically to augment the `arguments` object will pave the value at
// index `0` without incrimenting the other values's indexes.
// https://github.com/documentcloud/underscore/issues/9
var args = slice.call(arguments);
unshift.call(args, this._wrapped);
var result = func.apply(lodash, args);
return this._chain ? lodash(result).chain() : result;
};
}); });
} }
@@ -2193,7 +2253,9 @@
* // => 'nonsense' * // => 'nonsense'
*/ */
function result(object, property) { function result(object, property) {
if (object == null) return null; if (object == null) {
return null;
}
var value = object[property]; var value = object[property];
return isFunction(value) ? object[property]() : value; return isFunction(value) ? object[property]() : value;
} }
@@ -2212,8 +2274,11 @@
* _.times(3, function() { genie.grantWish(); }); * _.times(3, function() { genie.grantWish(); });
*/ */
function times(n, callback, thisArg) { function times(n, callback, thisArg) {
if (thisArg) {
callback = bind(callback, thisArg);
}
for (var index = 0; index < n; index++) { for (var index = 0; index < n; index++) {
callback.call(thisArg, index); callback(index);
} }
} }
@@ -2345,14 +2410,14 @@
* @example * @example
* *
* var stooges = [ * var stooges = [
* { 'name' : 'moe', 'age' : 40}, * { 'name': 'moe', 'age': 40 },
* { 'name' : 'larry', 'age' : 50}, * { 'name': 'larry', 'age': 50 },
* { 'name' : 'curly', 'age' : 60} * { 'name': 'curly', 'age': 60 }
* ]; * ];
* *
* var youngest = _.chain(stooges) * var youngest = _.chain(stooges)
* .sortBy(function(stooge){ return stooge.age; }) * .sortBy(function(stooge) { return stooge.age; })
* .map(function(stooge){ return stooge.name + ' is ' + stooge.age; }) * .map(function(stooge) { return stooge.name + ' is ' + stooge.age; })
* .first() * .first()
* .value(); * .value();
* // => 'moe is 40' * // => 'moe is 40'
@@ -2544,22 +2609,31 @@
lodash.mixin(lodash); lodash.mixin(lodash);
// Add all mutator Array functions to the wrapper. // Add all mutator Array functions to the wrapper.
forEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { forEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
var method = ArrayProto[name]; var func = ArrayProto[methodName];
Wrapper.prototype[name] = function() { Wrapper.prototype[methodName] = function() {
var wrapped = this._wrapped; var wrapped = this._wrapped;
method.apply(wrapped, arguments); func.apply(wrapped, arguments);
// IE compatibility mode and IE < 9 have buggy Array `shift()` and `splice()`
// functions that fail to remove the last element, `object[0]`, of
// array-like-objects even though the `length` property is set to `0`.
// The `shift()` method is buggy in IE 8 compatibility mode, while `splice()`
// is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9.
var length = wrapped.length; var length = wrapped.length;
if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0]; if (length === 0) {
return resultWrapper(wrapped, this._chain); delete wrapped[0];
}
return this._chain ? lodash(wrapped).chain() : wrapped;
}; };
}); });
// Add all accessor Array functions to the wrapper. // Add all accessor Array functions to the wrapper.
forEach(['concat', 'join', 'slice'], function(name) { forEach(['concat', 'join', 'slice'], function(methodName) {
var method = ArrayProto[name]; var func = ArrayProto[methodName];
Wrapper.prototype[name] = function() { lodash.prototype[methodName] = function() {
return resultWrapper(method.apply(this._wrapped, arguments), this._chain); var result = func.apply(this._wrapped, arguments);
return this._chain ? lodash(result).chain() : result;
}; };
}); });