"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "vendor/underscore/underscore.js" between
lodash-3.0.0.tar.gz and lodash-4.0.0.tar.gz

About: lodash is a modern JavaScript utility library delivering modularity, performance, & extras.

underscore.js  (lodash-3.0.0):underscore.js  (lodash-4.0.0)
// Underscore.js 1.7.0 // Underscore.js 1.8.3
// http://underscorejs.org // http://underscorejs.org
// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors // (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Underscore may be freely distributed under the MIT license. // Underscore may be freely distributed under the MIT license.
(function() { (function() {
// Baseline setup // Baseline setup
// -------------- // --------------
// Establish the root object, `window` in the browser, or `exports` on the ser // Establish the root object, `window` (`self`) in the browser, `global`
ver. // on the server, or `this` in some virtual machines. We use `self`
var root = this; // instead of `window` for `WebWorker` support.
var root = typeof self == 'object' && self.self === self && self ||
typeof global == 'object' && global.global === global && global ||
this;
// Save the previous value of the `_` variable. // Save the previous value of the `_` variable.
var previousUnderscore = root._; var previousUnderscore = root._;
// Save bytes in the minified (but not gzipped) version: // Save bytes in the minified (but not gzipped) version:
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Fun ction.prototype; var ArrayProto = Array.prototype, ObjProto = Object.prototype;
// Create quick reference variables for speed access to core prototypes. // Create quick reference variables for speed access to core prototypes.
var var push = ArrayProto.push,
push = ArrayProto.push, slice = ArrayProto.slice,
slice = ArrayProto.slice, toString = ObjProto.toString,
concat = ArrayProto.concat, hasOwnProperty = ObjProto.hasOwnProperty;
toString = ObjProto.toString,
hasOwnProperty = ObjProto.hasOwnProperty;
// All **ECMAScript 5** native function implementations that we hope to use // All **ECMAScript 5** native function implementations that we hope to use
// are declared here. // are declared here.
var var nativeIsArray = Array.isArray,
nativeIsArray = Array.isArray, nativeKeys = Object.keys,
nativeKeys = Object.keys, nativeCreate = Object.create;
nativeBind = FuncProto.bind;
// Naked function reference for surrogate-prototype-swapping.
var Ctor = function(){};
// Create a safe reference to the Underscore object for use below. // Create a safe reference to the Underscore object for use below.
var _ = function(obj) { var _ = function(obj) {
if (obj instanceof _) return obj; if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj); if (!(this instanceof _)) return new _(obj);
this._wrapped = obj; this._wrapped = obj;
}; };
// Export the Underscore object for **Node.js**, with // Export the Underscore object for **Node.js**, with
// backwards-compatibility for the old `require()` API. If we're in // backwards-compatibility for their old module API. If we're in
// the browser, add `_` as a global object. // the browser, add `_` as a global object.
if (typeof exports !== 'undefined') { // (`nodeType` is checked to ensure that `module`
if (typeof module !== 'undefined' && module.exports) { // and `exports` are not HTML elements.)
if (typeof exports != 'undefined' && !exports.nodeType) {
if (typeof module != 'undefined' && !module.nodeType && module.exports) {
exports = module.exports = _; exports = module.exports = _;
} }
exports._ = _; exports._ = _;
} else { } else {
root._ = _; root._ = _;
} }
// Current version. // Current version.
_.VERSION = '1.7.0'; _.VERSION = '1.8.3';
// Internal function that returns an efficient (for current engines) version // Internal function that returns an efficient (for current engines) version
// of the passed-in callback, to be repeatedly applied in other Underscore // of the passed-in callback, to be repeatedly applied in other Underscore
// functions. // functions.
var createCallback = function(func, context, argCount) { var optimizeCb = function(func, context, argCount) {
if (context === void 0) return func; if (context === void 0) return func;
switch (argCount == null ? 3 : argCount) { switch (argCount == null ? 3 : argCount) {
case 1: return function(value) { case 1: return function(value) {
return func.call(context, value); return func.call(context, value);
}; };
case 2: return function(value, other) { // The 2-parameter case has been omitted only because no current consumers
return func.call(context, value, other); // made use of it.
};
case 3: return function(value, index, collection) { case 3: return function(value, index, collection) {
return func.call(context, value, index, collection); return func.call(context, value, index, collection);
}; };
case 4: return function(accumulator, value, index, collection) { case 4: return function(accumulator, value, index, collection) {
return func.call(context, accumulator, value, index, collection); return func.call(context, accumulator, value, index, collection);
}; };
} }
return function() { return function() {
return func.apply(context, arguments); return func.apply(context, arguments);
}; };
}; };
// A mostly-internal function to generate callbacks that can be applied // An internal function to generate callbacks that can be applied to each
// to each element in a collection, returning the desired result — either // element in a collection, returning the desired result — either `identity`,
// identity, an arbitrary callback, a property matcher, or a property accessor // an arbitrary callback, a property matcher, or a property accessor.
. var cb = function(value, context, argCount) {
_.iteratee = function(value, context, argCount) {
if (value == null) return _.identity; if (value == null) return _.identity;
if (_.isFunction(value)) return createCallback(value, context, argCount); if (_.isFunction(value)) return optimizeCb(value, context, argCount);
if (_.isObject(value)) return _.matches(value); if (_.isObject(value)) return _.matcher(value);
return _.property(value); return _.property(value);
}; };
// An external wrapper for the internal callback generator
_.iteratee = function(value, context) {
return cb(value, context, Infinity);
};
// Similar to ES6's rest param (http://ariya.ofilabs.com/2013/03/es6-and-rest-
parameter.html)
// This accumulates the arguments passed into an array, after a given index.
var restArgs = function(func, startIndex) {
startIndex = startIndex == null ? func.length - 1 : +startIndex;
return function() {
var length = Math.max(arguments.length - startIndex, 0);
var rest = Array(length);
for (var index = 0; index < length; index++) {
rest[index] = arguments[index + startIndex];
}
switch (startIndex) {
case 0: return func.call(this, rest);
case 1: return func.call(this, arguments[0], rest);
case 2: return func.call(this, arguments[0], arguments[1], rest);
}
var args = Array(startIndex + 1);
for (index = 0; index < startIndex; index++) {
args[index] = arguments[index];
}
args[startIndex] = rest;
return func.apply(this, args);
};
};
// An internal function for creating a new object that inherits from another.
var baseCreate = function(prototype) {
if (!_.isObject(prototype)) return {};
if (nativeCreate) return nativeCreate(prototype);
Ctor.prototype = prototype;
var result = new Ctor;
Ctor.prototype = null;
return result;
};
var property = function(key) {
return function(obj) {
return obj == null ? void 0 : obj[key];
};
};
// Helper for collection methods to determine whether a collection
// 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
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var getLength = property('length');
var isArrayLike = function(collection) {
var length = getLength(collection);
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX
;
};
// Collection Functions // Collection Functions
// -------------------- // --------------------
// The cornerstone, an `each` implementation, aka `forEach`. // The cornerstone, an `each` implementation, aka `forEach`.
// Handles raw objects in addition to array-likes. Treats all // Handles raw objects in addition to array-likes. Treats all
// sparse array-likes as if they were dense. // sparse array-likes as if they were dense.
_.each = _.forEach = function(obj, iteratee, context) { _.each = _.forEach = function(obj, iteratee, context) {
if (obj == null) return obj; iteratee = optimizeCb(iteratee, context);
iteratee = createCallback(iteratee, context); var i, length;
var i, length = obj.length; if (isArrayLike(obj)) {
if (length === +length) { for (i = 0, length = obj.length; i < length; i++) {
for (i = 0; i < length; i++) {
iteratee(obj[i], i, obj); iteratee(obj[i], i, obj);
} }
} else { } else {
var keys = _.keys(obj); var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) { for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj); iteratee(obj[keys[i]], keys[i], obj);
} }
} }
return obj; return obj;
}; };
// Return the results of applying the iteratee to each element. // Return the results of applying the iteratee to each element.
_.map = _.collect = function(obj, iteratee, context) { _.map = _.collect = function(obj, iteratee, context) {
if (obj == null) return []; iteratee = cb(iteratee, context);
iteratee = _.iteratee(iteratee, context); var keys = !isArrayLike(obj) && _.keys(obj),
var keys = obj.length !== +obj.length && _.keys(obj),
length = (keys || obj).length, length = (keys || obj).length,
results = Array(length), results = Array(length);
currentKey;
for (var index = 0; index < length; index++) { for (var index = 0; index < length; index++) {
currentKey = keys ? keys[index] : index; var currentKey = keys ? keys[index] : index;
results[index] = iteratee(obj[currentKey], currentKey, obj); results[index] = iteratee(obj[currentKey], currentKey, obj);
} }
return results; return results;
}; };
var reduceError = 'Reduce of empty array with no initial value'; // Create a reducing function iterating left or right.
var createReduce = function(dir) {
// Wrap code that reassigns argument variables in a separate function than
// the one that accesses `arguments.length` to avoid a perf hit. (#1991)
var reducer = function(obj, iteratee, memo, initial) {
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length,
index = dir > 0 ? 0 : length - 1;
if (!initial) {
memo = obj[keys ? keys[index] : index];
index += dir;
}
for (; index >= 0 && index < length; index += dir) {
var currentKey = keys ? keys[index] : index;
memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
return memo;
};
return function(obj, iteratee, memo, context) {
var initial = arguments.length >= 3;
return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial);
};
};
// **Reduce** builds up a single result from a list of values, aka `inject`, // **Reduce** builds up a single result from a list of values, aka `inject`,
// or `foldl`. // or `foldl`.
_.reduce = _.foldl = _.inject = function(obj, iteratee, memo, context) { _.reduce = _.foldl = _.inject = createReduce(1);
if (obj == null) obj = [];
iteratee = createCallback(iteratee, context, 4);
var keys = obj.length !== +obj.length && _.keys(obj),
length = (keys || obj).length,
index = 0, currentKey;
if (arguments.length < 3) {
if (!length) throw new TypeError(reduceError);
memo = obj[keys ? keys[index++] : index++];
}
for (; index < length; index++) {
currentKey = keys ? keys[index] : index;
memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
return memo;
};
// The right-associative version of reduce, also known as `foldr`. // The right-associative version of reduce, also known as `foldr`.
_.reduceRight = _.foldr = function(obj, iteratee, memo, context) { _.reduceRight = _.foldr = createReduce(-1);
if (obj == null) obj = [];
iteratee = createCallback(iteratee, context, 4);
var keys = obj.length !== + obj.length && _.keys(obj),
index = (keys || obj).length,
currentKey;
if (arguments.length < 3) {
if (!index) throw new TypeError(reduceError);
memo = obj[keys ? keys[--index] : --index];
}
while (index--) {
currentKey = keys ? keys[index] : index;
memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
return memo;
};
// Return the first value which passes a truth test. Aliased as `detect`. // Return the first value which passes a truth test. Aliased as `detect`.
_.find = _.detect = function(obj, predicate, context) { _.find = _.detect = function(obj, predicate, context) {
var result; var key;
predicate = _.iteratee(predicate, context); if (isArrayLike(obj)) {
_.some(obj, function(value, index, list) { key = _.findIndex(obj, predicate, context);
if (predicate(value, index, list)) { } else {
result = value; key = _.findKey(obj, predicate, context);
return true; }
} if (key !== void 0 && key !== -1) return obj[key];
});
return result;
}; };
// Return all the elements that pass a truth test. // Return all the elements that pass a truth test.
// Aliased as `select`. // Aliased as `select`.
_.filter = _.select = function(obj, predicate, context) { _.filter = _.select = function(obj, predicate, context) {
var results = []; var results = [];
if (obj == null) return results; predicate = cb(predicate, context);
predicate = _.iteratee(predicate, context);
_.each(obj, function(value, index, list) { _.each(obj, function(value, index, list) {
if (predicate(value, index, list)) results.push(value); if (predicate(value, index, list)) results.push(value);
}); });
return results; return results;
}; };
// Return all the elements for which a truth test fails. // Return all the elements for which a truth test fails.
_.reject = function(obj, predicate, context) { _.reject = function(obj, predicate, context) {
return _.filter(obj, _.negate(_.iteratee(predicate)), context); return _.filter(obj, _.negate(cb(predicate)), context);
}; };
// Determine whether all of the elements match a truth test. // Determine whether all of the elements match a truth test.
// Aliased as `all`. // Aliased as `all`.
_.every = _.all = function(obj, predicate, context) { _.every = _.all = function(obj, predicate, context) {
if (obj == null) return true; predicate = cb(predicate, context);
predicate = _.iteratee(predicate, context); var keys = !isArrayLike(obj) && _.keys(obj),
var keys = obj.length !== +obj.length && _.keys(obj), length = (keys || obj).length;
length = (keys || obj).length, for (var index = 0; index < length; index++) {
index, currentKey; var currentKey = keys ? keys[index] : index;
for (index = 0; index < length; index++) {
currentKey = keys ? keys[index] : index;
if (!predicate(obj[currentKey], currentKey, obj)) return false; if (!predicate(obj[currentKey], currentKey, obj)) return false;
} }
return true; return true;
}; };
// Determine if at least one element in the object matches a truth test. // Determine if at least one element in the object matches a truth test.
// Aliased as `any`. // Aliased as `any`.
_.some = _.any = function(obj, predicate, context) { _.some = _.any = function(obj, predicate, context) {
if (obj == null) return false; predicate = cb(predicate, context);
predicate = _.iteratee(predicate, context); var keys = !isArrayLike(obj) && _.keys(obj),
var keys = obj.length !== +obj.length && _.keys(obj), length = (keys || obj).length;
length = (keys || obj).length, for (var index = 0; index < length; index++) {
index, currentKey; var currentKey = keys ? keys[index] : index;
for (index = 0; index < length; index++) {
currentKey = keys ? keys[index] : index;
if (predicate(obj[currentKey], currentKey, obj)) return true; if (predicate(obj[currentKey], currentKey, obj)) return true;
} }
return false; return false;
}; };
// Determine if the array or object contains a given value (using `===`). // Determine if the array or object contains a given item (using `===`).
// Aliased as `include`. // Aliased as `includes` and `include`.
_.contains = _.include = function(obj, target) { _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
if (obj == null) return false; if (!isArrayLike(obj)) obj = _.values(obj);
if (obj.length !== +obj.length) obj = _.values(obj); if (typeof fromIndex != 'number' || guard) fromIndex = 0;
return _.indexOf(obj, target) >= 0; return _.indexOf(obj, item, fromIndex) >= 0;
}; };
// Invoke a method (with arguments) on every item in a collection. // Invoke a method (with arguments) on every item in a collection.
_.invoke = function(obj, method) { _.invoke = restArgs(function(obj, method, args) {
var args = slice.call(arguments, 2);
var isFunc = _.isFunction(method); var isFunc = _.isFunction(method);
return _.map(obj, function(value) { return _.map(obj, function(value) {
return (isFunc ? method : value[method]).apply(value, args); var func = isFunc ? method : value[method];
return func == null ? func : func.apply(value, args);
}); });
}; });
// Convenience version of a common use case of `map`: fetching a property. // Convenience version of a common use case of `map`: fetching a property.
_.pluck = function(obj, key) { _.pluck = function(obj, key) {
return _.map(obj, _.property(key)); return _.map(obj, _.property(key));
}; };
// Convenience version of a common use case of `filter`: selecting only object s // Convenience version of a common use case of `filter`: selecting only object s
// containing specific `key:value` pairs. // containing specific `key:value` pairs.
_.where = function(obj, attrs) { _.where = function(obj, attrs) {
return _.filter(obj, _.matches(attrs)); return _.filter(obj, _.matcher(attrs));
}; };
// Convenience version of a common use case of `find`: getting the first objec t // Convenience version of a common use case of `find`: getting the first objec t
// containing specific `key:value` pairs. // containing specific `key:value` pairs.
_.findWhere = function(obj, attrs) { _.findWhere = function(obj, attrs) {
return _.find(obj, _.matches(attrs)); return _.find(obj, _.matcher(attrs));
}; };
// Return the maximum element (or element-based computation). // Return the maximum element (or element-based computation).
_.max = function(obj, iteratee, context) { _.max = function(obj, iteratee, context) {
var result = -Infinity, lastComputed = -Infinity, var result = -Infinity, lastComputed = -Infinity,
value, computed; value, computed;
if (iteratee == null && obj != null) { if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'ob
obj = obj.length === +obj.length ? obj : _.values(obj); ject') && obj != null) {
obj = isArrayLike(obj) ? obj : _.values(obj);
for (var i = 0, length = obj.length; i < length; i++) { for (var i = 0, length = obj.length; i < length; i++) {
value = obj[i]; value = obj[i];
if (value > result) { if (value != null && value > result) {
result = value; result = value;
} }
} }
} else { } else {
iteratee = _.iteratee(iteratee, context); iteratee = cb(iteratee, context);
_.each(obj, function(value, index, list) { _.each(obj, function(v, index, list) {
computed = iteratee(value, index, list); computed = iteratee(v, index, list);
if (computed > lastComputed || computed === -Infinity && result === -Inf inity) { if (computed > lastComputed || computed === -Infinity && result === -Inf inity) {
result = value; result = v;
lastComputed = computed; lastComputed = computed;
} }
}); });
} }
return result; return result;
}; };
// Return the minimum element (or element-based computation). // Return the minimum element (or element-based computation).
_.min = function(obj, iteratee, context) { _.min = function(obj, iteratee, context) {
var result = Infinity, lastComputed = Infinity, var result = Infinity, lastComputed = Infinity,
value, computed; value, computed;
if (iteratee == null && obj != null) { if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'ob
obj = obj.length === +obj.length ? obj : _.values(obj); ject') && obj != null) {
obj = isArrayLike(obj) ? obj : _.values(obj);
for (var i = 0, length = obj.length; i < length; i++) { for (var i = 0, length = obj.length; i < length; i++) {
value = obj[i]; value = obj[i];
if (value < result) { if (value != null && value < result) {
result = value; result = value;
} }
} }
} else { } else {
iteratee = _.iteratee(iteratee, context); iteratee = cb(iteratee, context);
_.each(obj, function(value, index, list) { _.each(obj, function(v, index, list) {
computed = iteratee(value, index, list); computed = iteratee(v, index, list);
if (computed < lastComputed || computed === Infinity && result === Infin ity) { if (computed < lastComputed || computed === Infinity && result === Infin ity) {
result = value; result = v;
lastComputed = computed; lastComputed = computed;
} }
}); });
} }
return result; return result;
}; };
// Shuffle a collection, using the modern version of the // Shuffle a collection.
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
_.shuffle = function(obj) { _.shuffle = function(obj) {
var set = obj && obj.length === +obj.length ? obj : _.values(obj); return _.sample(obj, Infinity);
var length = set.length;
var shuffled = Array(length);
for (var index = 0, rand; index < length; index++) {
rand = _.random(0, index);
if (rand !== index) shuffled[index] = shuffled[rand];
shuffled[rand] = set[index];
}
return shuffled;
}; };
// Sample **n** random values from a collection. // Sample **n** random values from a collection using the modern version of th
e
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
// If **n** is not specified, returns a single random element. // If **n** is not specified, returns a single random element.
// The internal `guard` argument allows it to work with `map`. // The internal `guard` argument allows it to work with `map`.
_.sample = function(obj, n, guard) { _.sample = function(obj, n, guard) {
if (n == null || guard) { if (n == null || guard) {
if (obj.length !== +obj.length) obj = _.values(obj); if (!isArrayLike(obj)) obj = _.values(obj);
return obj[_.random(obj.length - 1)]; return obj[_.random(obj.length - 1)];
} }
return _.shuffle(obj).slice(0, Math.max(0, n)); var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj);
var length = getLength(sample);
n = Math.max(Math.min(n, length), 0);
var last = length - 1;
for (var index = 0; index < n; index++) {
var rand = _.random(index, last);
var temp = sample[index];
sample[index] = sample[rand];
sample[rand] = temp;
}
return sample.slice(0, n);
}; };
// Sort the object's values by a criterion produced by an iteratee. // Sort the object's values by a criterion produced by an iteratee.
_.sortBy = function(obj, iteratee, context) { _.sortBy = function(obj, iteratee, context) {
iteratee = _.iteratee(iteratee, context); var index = 0;
return _.pluck(_.map(obj, function(value, index, list) { iteratee = cb(iteratee, context);
return _.pluck(_.map(obj, function(value, key, list) {
return { return {
value: value, value: value,
index: index, index: index++,
criteria: iteratee(value, index, list) criteria: iteratee(value, key, list)
}; };
}).sort(function(left, right) { }).sort(function(left, right) {
var a = left.criteria; var a = left.criteria;
var b = right.criteria; var b = right.criteria;
if (a !== b) { if (a !== b) {
if (a > b || a === void 0) return 1; if (a > b || a === void 0) return 1;
if (a < b || b === void 0) return -1; if (a < b || b === void 0) return -1;
} }
return left.index - right.index; return left.index - right.index;
}), 'value'); }), 'value');
}; };
// An internal function used for aggregate "group by" operations. // An internal function used for aggregate "group by" operations.
var group = function(behavior) { var group = function(behavior, partition) {
return function(obj, iteratee, context) { return function(obj, iteratee, context) {
var result = {}; var result = partition ? [[], []] : {};
iteratee = _.iteratee(iteratee, context); iteratee = cb(iteratee, context);
_.each(obj, function(value, index) { _.each(obj, function(value, index) {
var key = iteratee(value, index, obj); var key = iteratee(value, index, obj);
behavior(result, value, key); behavior(result, value, key);
}); });
return result; return result;
}; };
}; };
// Groups the object's values by a criterion. Pass either a string attribute // Groups the object's values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion. // to group by, or a function that returns the criterion.
skipping to change at line 389 skipping to change at line 436
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.
_.countBy = group(function(result, value, key) { _.countBy = group(function(result, value, key) {
if (_.has(result, key)) result[key]++; else result[key] = 1; if (_.has(result, key)) result[key]++; else result[key] = 1;
}); });
// Use a comparator function to figure out the smallest index at which var reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\ud
// an object should be inserted so as to maintain order. Uses binary search. fff]/g;
_.sortedIndex = function(array, obj, iteratee, context) {
iteratee = _.iteratee(iteratee, context, 1);
var value = iteratee(obj);
var low = 0, high = array.length;
while (low < high) {
var mid = low + high >>> 1;
if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
}
return low;
};
// Safely create a real, live array from anything iterable. // Safely create a real, live array from anything iterable.
_.toArray = function(obj) { _.toArray = function(obj) {
if (!obj) return []; if (!obj) return [];
if (_.isArray(obj)) return slice.call(obj); if (_.isArray(obj)) return slice.call(obj);
if (obj.length === +obj.length) return _.map(obj, _.identity); if (_.isString(obj)) {
// Keep surrogate pair characters together
return obj.match(reStrSymbol);
}
if (isArrayLike(obj)) return _.map(obj, _.identity);
return _.values(obj); return _.values(obj);
}; };
// Return the number of elements in an object. // Return the number of elements in an object.
_.size = function(obj) { _.size = function(obj) {
if (obj == null) return 0; if (obj == null) return 0;
return obj.length === +obj.length ? obj.length : _.keys(obj).length; return isArrayLike(obj) ? obj.length : _.keys(obj).length;
}; };
// Split a collection into two arrays: one whose elements all satisfy the give n // Split a collection into two arrays: one whose elements all satisfy the give n
// predicate, and one whose elements all do not satisfy the predicate. // predicate, and one whose elements all do not satisfy the predicate.
_.partition = function(obj, predicate, context) { _.partition = group(function(result, value, pass) {
predicate = _.iteratee(predicate, context); result[pass ? 0 : 1].push(value);
var pass = [], fail = []; }, true);
_.each(obj, function(value, key, obj) {
(predicate(value, key, obj) ? pass : fail).push(value);
});
return [pass, fail];
};
// Array Functions // Array Functions
// --------------- // ---------------
// Get the first element of an array. Passing **n** will return the first N // Get the first element of an array. Passing **n** will return the first N
// values in the array. Aliased as `head` and `take`. The **guard** check // values in the array. Aliased as `head` and `take`. The **guard** check
// allows it to work with `_.map`. // allows it to work with `_.map`.
_.first = _.head = _.take = function(array, n, guard) { _.first = _.head = _.take = function(array, n, guard) {
if (array == null) return void 0; if (array == null) return void 0;
if (n == null || guard) return array[0]; if (n == null || guard) return array[0];
if (n < 0) return []; return _.initial(array, array.length - n);
return slice.call(array, 0, n);
}; };
// Returns everything but the last entry of the array. Especially useful on // Returns everything but the last entry of the array. Especially useful on
// the arguments object. Passing **n** will return all the values in // the arguments object. Passing **n** will return all the values in
// the array, excluding the last N. The **guard** check allows it to work with // the array, excluding the last N.
// `_.map`.
_.initial = function(array, n, guard) { _.initial = function(array, n, guard) {
return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
}; };
// Get the last element of an array. Passing **n** will return the last N // Get the last element of an array. Passing **n** will return the last N
// values in the array. The **guard** check allows it to work with `_.map`. // values in the array.
_.last = function(array, n, guard) { _.last = function(array, n, guard) {
if (array == null) return void 0; if (array == null) return void 0;
if (n == null || guard) return array[array.length - 1]; if (n == null || guard) return array[array.length - 1];
return slice.call(array, Math.max(array.length - n, 0)); return _.rest(array, Math.max(0, array.length - n));
}; };
// Returns everything but the first entry of the array. Aliased as `tail` and `drop`. // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
// Especially useful on the arguments object. Passing an **n** will return // Especially useful on the arguments object. Passing an **n** will return
// the rest N values in the array. The **guard** // the rest N values in the array.
// check allows it to work with `_.map`.
_.rest = _.tail = _.drop = function(array, n, guard) { _.rest = _.tail = _.drop = function(array, n, guard) {
return slice.call(array, n == null || guard ? 1 : n); return slice.call(array, n == null || guard ? 1 : n);
}; };
// Trim out all falsy values from an array. // Trim out all falsy values from an array.
_.compact = function(array) { _.compact = function(array) {
return _.filter(array, _.identity); return _.filter(array, _.identity);
}; };
// Internal implementation of a recursive `flatten` function. // Internal implementation of a recursive `flatten` function.
var flatten = function(input, shallow, strict, output) { var flatten = function(input, shallow, strict, output) {
if (shallow && _.every(input, _.isArray)) { output = output || [];
return concat.apply(output, input); var idx = output.length;
} for (var i = 0, length = getLength(input); i < length; i++) {
for (var i = 0, length = input.length; i < length; i++) {
var value = input[i]; var value = input[i];
if (!_.isArray(value) && !_.isArguments(value)) { if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
if (!strict) output.push(value); // Flatten current level of array or arguments object
} else if (shallow) { if (shallow) {
push.apply(output, value); var j = 0, len = value.length;
} else { while (j < len) output[idx++] = value[j++];
flatten(value, shallow, strict, output); } else {
flatten(value, shallow, strict, output);
idx = output.length;
}
} else if (!strict) {
output[idx++] = value;
} }
} }
return output; return output;
}; };
// Flatten out an array, either recursively (by default), or just one level. // Flatten out an array, either recursively (by default), or just one level.
_.flatten = function(array, shallow) { _.flatten = function(array, shallow) {
return flatten(array, shallow, false, []); return flatten(array, shallow, false);
}; };
// Return a version of the array that does not contain the specified value(s). // Return a version of the array that does not contain the specified value(s).
_.without = function(array) { _.without = restArgs(function(array, otherArrays) {
return _.difference(array, slice.call(arguments, 1)); return _.difference(array, otherArrays);
}; });
// Produce a duplicate-free version of the array. If the array has already // Produce a duplicate-free version of the array. If the array has already
// been sorted, you have the option of using a faster algorithm. // been sorted, you have the option of using a faster algorithm.
// Aliased as `unique`. // Aliased as `unique`.
_.uniq = _.unique = function(array, isSorted, iteratee, context) { _.uniq = _.unique = function(array, isSorted, iteratee, context) {
if (array == null) return [];
if (!_.isBoolean(isSorted)) { if (!_.isBoolean(isSorted)) {
context = iteratee; context = iteratee;
iteratee = isSorted; iteratee = isSorted;
isSorted = false; isSorted = false;
} }
if (iteratee != null) iteratee = _.iteratee(iteratee, context); if (iteratee != null) iteratee = cb(iteratee, context);
var result = []; var result = [];
var seen = []; var seen = [];
for (var i = 0, length = array.length; i < length; i++) { for (var i = 0, length = getLength(array); i < length; i++) {
var value = array[i]; var value = array[i],
computed = iteratee ? iteratee(value, i, array) : value;
if (isSorted) { if (isSorted) {
if (!i || seen !== value) result.push(value); if (!i || seen !== computed) result.push(value);
seen = value; seen = computed;
} else if (iteratee) { } else if (iteratee) {
var computed = iteratee(value, i, array); if (!_.contains(seen, computed)) {
if (_.indexOf(seen, computed) < 0) {
seen.push(computed); seen.push(computed);
result.push(value); result.push(value);
} }
} else if (_.indexOf(result, value) < 0) { } else if (!_.contains(result, value)) {
result.push(value); result.push(value);
} }
} }
return result; return result;
}; };
// Produce an array that contains the union: each distinct element from all of // Produce an array that contains the union: each distinct element from all of
// the passed-in arrays. // the passed-in arrays.
_.union = function() { _.union = restArgs(function(arrays) {
return _.uniq(flatten(arguments, true, true, [])); return _.uniq(flatten(arrays, true, true));
}; });
// Produce an array that contains every item shared between all the // Produce an array that contains every item shared between all the
// passed-in arrays. // passed-in arrays.
_.intersection = function(array) { _.intersection = function(array) {
if (array == null) return [];
var result = []; var result = [];
var argsLength = arguments.length; var argsLength = arguments.length;
for (var i = 0, length = array.length; i < length; i++) { for (var i = 0, length = getLength(array); i < length; i++) {
var item = array[i]; var item = array[i];
if (_.contains(result, item)) continue; if (_.contains(result, item)) continue;
for (var j = 1; j < argsLength; j++) { var j;
for (j = 1; j < argsLength; j++) {
if (!_.contains(arguments[j], item)) break; if (!_.contains(arguments[j], item)) break;
} }
if (j === argsLength) result.push(item); if (j === argsLength) result.push(item);
} }
return result; return result;
}; };
// Take the difference between one array and a number of other arrays. // Take the difference between one array and a number of other arrays.
// Only the elements present in just the first array will remain. // Only the elements present in just the first array will remain.
_.difference = function(array) { _.difference = restArgs(function(array, rest) {
var rest = flatten(slice.call(arguments, 1), true, true, []); rest = flatten(rest, true, true);
return _.filter(array, function(value){ return _.filter(array, function(value){
return !_.contains(rest, value); return !_.contains(rest, value);
}); });
});
// Complement of _.zip. Unzip accepts an array of arrays and groups
// each array's elements on shared indices
_.unzip = function(array) {
var length = array && _.max(array, getLength).length || 0;
var result = Array(length);
for (var index = 0; index < length; index++) {
result[index] = _.pluck(array, index);
}
return result;
}; };
// Zip together multiple lists into a single array -- elements that share // Zip together multiple lists into a single array -- elements that share
// an index go together. // an index go together.
_.zip = function(array) { _.zip = restArgs(_.unzip);
if (array == null) return [];
var length = _.max(arguments, 'length').length;
var results = Array(length);
for (var i = 0; i < length; i++) {
results[i] = _.pluck(arguments, i);
}
return results;
};
// Converts lists into objects. Pass either a single array of `[key, value]` // Converts lists into objects. Pass either a single array of `[key, value]`
// pairs, or two parallel arrays of the same length -- one of keys, and one of // pairs, or two parallel arrays of the same length -- one of keys, and one of
// the corresponding values. // the corresponding values.
_.object = function(list, values) { _.object = function(list, values) {
if (list == null) return {};
var result = {}; var result = {};
for (var i = 0, length = list.length; i < length; i++) { for (var i = 0, length = getLength(list); i < length; i++) {
if (values) { if (values) {
result[list[i]] = values[i]; result[list[i]] = values[i];
} else { } else {
result[list[i][0]] = list[i][1]; result[list[i][0]] = list[i][1];
} }
} }
return result; return result;
}; };
// Return the position of the first occurrence of an item in an array, // Generator function to create the findIndex and findLastIndex functions
// or -1 if the item is not included in the array. var createPredicateIndexFinder = function(dir) {
// If the array is large and already in sort order, pass `true` return function(array, predicate, context) {
// for **isSorted** to use binary search. predicate = cb(predicate, context);
_.indexOf = function(array, item, isSorted) { var length = getLength(array);
if (array == null) return -1; var index = dir > 0 ? 0 : length - 1;
var i = 0, length = array.length; for (; index >= 0 && index < length; index += dir) {
if (isSorted) { if (predicate(array[index], index, array)) return index;
if (typeof isSorted == 'number') { }
i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted; return -1;
} else { };
i = _.sortedIndex(array, item);
return array[i] === item ? i : -1;
}
}
for (; i < length; i++) if (array[i] === item) return i;
return -1;
}; };
_.lastIndexOf = function(array, item, from) { // Returns the first index on an array-like that passes a predicate test
if (array == null) return -1; _.findIndex = createPredicateIndexFinder(1);
var idx = array.length; _.findLastIndex = createPredicateIndexFinder(-1);
if (typeof from == 'number') {
idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 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.
_.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;
} }
while (--idx >= 0) if (array[idx] === item) return idx; return low;
return -1;
}; };
// 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.
_.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
_.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
// Generate an integer Array containing an arithmetic progression. A port of // Generate an integer Array containing an arithmetic progression. A port of
// the native Python `range()` function. See // the native Python `range()` function. See
// [the Python documentation](http://docs.python.org/library/functions.html#ra nge). // [the Python documentation](http://docs.python.org/library/functions.html#ra nge).
_.range = function(start, stop, step) { _.range = function(start, stop, step) {
if (arguments.length <= 1) { if (stop == null) {
stop = start || 0; stop = start || 0;
start = 0; start = 0;
} }
step = step || 1; if (!step) {
step = stop < start ? -1 : 1;
}
var length = Math.max(Math.ceil((stop - start) / step), 0); var length = Math.max(Math.ceil((stop - start) / step), 0);
var range = Array(length); var range = Array(length);
for (var idx = 0; idx < length; idx++, start += step) { for (var idx = 0; idx < length; idx++, start += step) {
range[idx] = start; range[idx] = start;
} }
return range; return range;
}; };
// Split an **array** into several arrays containing **count** or less element
s
// of initial array
_.chunk = function(array, count) {
if (count == null || count < 1) return [];
var result = [];
var i = 0, length = array.length;
while (i < length) {
result.push(slice.call(array, i, i += count));
}
return result;
};
// Function (ahem) Functions // Function (ahem) Functions
// ------------------ // ------------------
// Reusable constructor function for prototype setting. // Determines whether to execute a function as a constructor
var Ctor = function(){}; // or a normal function with the provided arguments
var executeBound = function(sourceFunc, boundFunc, context, callingContext, ar
gs) {
if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context,
args);
var self = baseCreate(sourceFunc.prototype);
var result = sourceFunc.apply(self, args);
if (_.isObject(result)) return result;
return self;
};
// Create a function bound to a given object (assigning `this`, and arguments, // Create a function bound to a given object (assigning `this`, and arguments,
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
// available. // available.
_.bind = function(func, context) { _.bind = restArgs(function(func, context, args) {
var args, bound;
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, sl
ice.call(arguments, 1));
if (!_.isFunction(func)) throw new TypeError('Bind must be called on a funct ion'); if (!_.isFunction(func)) throw new TypeError('Bind must be called on a funct ion');
args = slice.call(arguments, 2); var bound = restArgs(function(callArgs) {
bound = function() { return executeBound(func, bound, context, this, args.concat(callArgs));
if (!(this instanceof bound)) return func.apply(context, args.concat(slice });
.call(arguments)));
Ctor.prototype = func.prototype;
var self = new Ctor;
Ctor.prototype = null;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (_.isObject(result)) return result;
return self;
};
return bound; return bound;
}; });
// Partially apply a function by creating a version that has had some of its // Partially apply a function by creating a version that has had some of its
// arguments pre-filled, without changing its dynamic `this` context. _ acts // arguments pre-filled, without changing its dynamic `this` context. _ acts
// as a placeholder, allowing any combination of arguments to be pre-filled. // as a placeholder by default, allowing any combination of arguments to be
_.partial = function(func) { // pre-filled. Set `_.partial.placeholder` for a custom placeholder argument.
var boundArgs = slice.call(arguments, 1); _.partial = restArgs(function(func, boundArgs) {
return function() { var placeholder = _.partial.placeholder;
var position = 0; var bound = function() {
var args = boundArgs.slice(); var position = 0, length = boundArgs.length;
for (var i = 0, length = args.length; i < length; i++) { var args = Array(length);
if (args[i] === _) args[i] = arguments[position++]; for (var i = 0; i < length; i++) {
args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundAr
gs[i];
} }
while (position < arguments.length) args.push(arguments[position++]); while (position < arguments.length) args.push(arguments[position++]);
return func.apply(this, args); return executeBound(func, bound, this, this, args);
}; };
}; return bound;
});
_.partial.placeholder = _;
// Bind a number of an object's methods to that object. Remaining arguments // Bind a number of an object's methods to that object. Remaining arguments
// are the method names to be bound. Useful for ensuring that all callbacks // are the method names to be bound. Useful for ensuring that all callbacks
// defined on an object belong to it. // defined on an object belong to it.
_.bindAll = function(obj) { _.bindAll = restArgs(function(obj, keys) {
var i, length = arguments.length, key; keys = flatten(keys, false, false);
if (length <= 1) throw new Error('bindAll must be passed function names'); var index = keys.length;
for (i = 1; i < length; i++) { if (index < 1) throw new Error('bindAll must be passed function names');
key = arguments[i]; while (index--) {
var key = keys[index];
obj[key] = _.bind(obj[key], obj); obj[key] = _.bind(obj[key], obj);
} }
return obj; });
};
// Memoize an expensive function by storing its results. // Memoize an expensive function by storing its results.
_.memoize = function(func, hasher) { _.memoize = function(func, hasher) {
var memoize = function(key) { var memoize = function(key) {
var cache = memoize.cache; var cache = memoize.cache;
var address = hasher ? hasher.apply(this, arguments) : key; var address = '' + (hasher ? hasher.apply(this, arguments) : key);
if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
return cache[address]; return cache[address];
}; };
memoize.cache = {}; memoize.cache = {};
return memoize; return memoize;
}; };
// Delays a function for the given number of milliseconds, and then calls // Delays a function for the given number of milliseconds, and then calls
// it with the arguments supplied. // it with the arguments supplied.
_.delay = function(func, wait) { _.delay = restArgs(function(func, wait, args) {
var args = slice.call(arguments, 2); return setTimeout(function() {
return setTimeout(function(){
return func.apply(null, args); return func.apply(null, args);
}, wait); }, wait);
}; });
// Defers a function, scheduling it to run after the current call stack has // Defers a function, scheduling it to run after the current call stack has
// cleared. // cleared.
_.defer = function(func) { _.defer = _.partial(_.delay, _, 1);
return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
};
// Returns a function, that, when invoked, will only be triggered at most once // Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time. Normally, the throttled function will run // during a given window of time. Normally, the throttled function will run
// as much as it can, without ever going more than once per `wait` duration; // as much as it can, without ever going more than once per `wait` duration;
// but if you'd like to disable the execution on the leading edge, pass // but if you'd like to disable the execution on the leading edge, pass
// `{leading: false}`. To disable execution on the trailing edge, ditto. // `{leading: false}`. To disable execution on the trailing edge, ditto.
_.throttle = function(func, wait, options) { _.throttle = function(func, wait, options) {
var context, args, result; var timeout, context, args, result;
var timeout = null;
var previous = 0; var previous = 0;
if (!options) options = {}; if (!options) options = {};
var later = function() { var later = function() {
previous = options.leading === false ? 0 : _.now(); previous = options.leading === false ? 0 : _.now();
timeout = null; timeout = null;
result = func.apply(context, args); result = func.apply(context, args);
if (!timeout) context = args = null; if (!timeout) context = args = null;
}; };
return function() {
var throttled = function() {
var now = _.now(); var now = _.now();
if (!previous && options.leading === false) previous = now; if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous); var remaining = wait - (now - previous);
context = this; context = this;
args = arguments; args = arguments;
if (remaining <= 0 || remaining > wait) { if (remaining <= 0 || remaining > wait) {
clearTimeout(timeout); if (timeout) {
timeout = null; clearTimeout(timeout);
timeout = null;
}
previous = now; previous = now;
result = func.apply(context, args); result = func.apply(context, args);
if (!timeout) context = args = null; if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) { } else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining); timeout = setTimeout(later, remaining);
} }
return result; return result;
}; };
throttled.cancel = function() {
clearTimeout(timeout);
previous = 0;
timeout = context = args = null;
};
return throttled;
}; };
// Returns a function, that, as long as it continues to be invoked, will not // Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for // be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the // N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing. // leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) { _.debounce = function(func, wait, immediate) {
var timeout, args, context, timestamp, result; var timeout, result;
var later = function() { var later = function(context, args) {
var last = _.now() - timestamp; timeout = null;
if (args) result = func.apply(context, args);
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
}; };
return function() { var debounced = restArgs(function(args) {
context = this;
args = arguments;
timestamp = _.now();
var callNow = immediate && !timeout; var callNow = immediate && !timeout;
if (!timeout) timeout = setTimeout(later, wait); if (timeout) clearTimeout(timeout);
if (callNow) { if (callNow) {
result = func.apply(context, args); timeout = setTimeout(later, wait);
context = args = null; result = func.apply(this, args);
} else if (!immediate) {
timeout = _.delay(later, wait, this, args);
} }
return result; return result;
});
debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
}; };
return debounced;
}; };
// Returns the first function passed as an argument to the second, // Returns the first function passed as an argument to the second,
// allowing you to adjust arguments, run code before and after, and // allowing you to adjust arguments, run code before and after, and
// conditionally execute the original function. // conditionally execute the original function.
_.wrap = function(func, wrapper) { _.wrap = function(func, wrapper) {
return _.partial(wrapper, func); return _.partial(wrapper, func);
}; };
// Returns a negated version of the passed-in predicate. // Returns a negated version of the passed-in predicate.
skipping to change at line 817 skipping to change at line 909
var args = arguments; var args = arguments;
var start = args.length - 1; var start = args.length - 1;
return function() { return function() {
var i = start; var i = start;
var result = args[start].apply(this, arguments); var result = args[start].apply(this, arguments);
while (i--) result = args[i].call(this, result); while (i--) result = args[i].call(this, result);
return result; return result;
}; };
}; };
// Returns a function that will only be executed after being called N times. // Returns a function that will only be executed on and after the Nth call.
_.after = function(times, func) { _.after = function(times, func) {
return function() { return function() {
if (--times < 1) { if (--times < 1) {
return func.apply(this, arguments); return func.apply(this, arguments);
} }
}; };
}; };
// Returns a function that will only be executed before being called N times. // Returns a function that will only be executed up to (but not including) the Nth call.
_.before = function(times, func) { _.before = function(times, func) {
var memo; var memo;
return function() { return function() {
if (--times > 0) { if (--times > 0) {
memo = func.apply(this, arguments); memo = func.apply(this, arguments);
} else {
func = null;
} }
if (times <= 1) func = null;
return memo; return memo;
}; };
}; };
// Returns a function that will be executed at most one time, no matter how // Returns a function that will be executed at most one time, no matter how
// often you call it. Useful for lazy initialization. // often you call it. Useful for lazy initialization.
_.once = _.partial(_.before, 2); _.once = _.partial(_.before, 2);
_.restArgs = restArgs;
// Object Functions // Object Functions
// ---------------- // ----------------
// Retrieve the names of an object's properties. // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'
];
var collectNonEnumProps = function(obj, keys) {
var nonEnumIdx = nonEnumerableProps.length;
var constructor = obj.constructor;
var proto = _.isFunction(constructor) && constructor.prototype || ObjProto;
// Constructor is a special case.
var prop = 'constructor';
if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
while (nonEnumIdx--) {
prop = nonEnumerableProps[nonEnumIdx];
if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
keys.push(prop);
}
}
};
// Retrieve the names of an object's own properties.
// Delegates to **ECMAScript 5**'s native `Object.keys` // Delegates to **ECMAScript 5**'s native `Object.keys`
_.keys = function(obj) { _.keys = function(obj) {
if (!_.isObject(obj)) return []; if (!_.isObject(obj)) return [];
if (nativeKeys) return nativeKeys(obj); if (nativeKeys) return nativeKeys(obj);
var keys = []; var keys = [];
for (var key in obj) if (_.has(obj, key)) keys.push(key); for (var key in obj) if (_.has(obj, key)) keys.push(key);
// Ahem, IE < 9.
if (hasEnumBug) collectNonEnumProps(obj, keys);
return keys;
};
// Retrieve all the property names of an object.
_.allKeys = function(obj) {
if (!_.isObject(obj)) return [];
var keys = [];
for (var key in obj) keys.push(key);
// Ahem, IE < 9.
if (hasEnumBug) collectNonEnumProps(obj, keys);
return keys; return keys;
}; };
// Retrieve the values of an object's properties. // Retrieve the values of an object's properties.
_.values = function(obj) { _.values = function(obj) {
var keys = _.keys(obj); var keys = _.keys(obj);
var length = keys.length; var length = keys.length;
var values = Array(length); var values = Array(length);
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
values[i] = obj[keys[i]]; values[i] = obj[keys[i]];
} }
return values; return values;
}; };
// Returns the results of applying the iteratee to each element of the object
// In contrast to _.map it returns an object
_.mapObject = function(obj, iteratee, context) {
iteratee = cb(iteratee, context);
var keys = _.keys(obj),
length = keys.length,
results = {};
for (var index = 0; index < length; index++) {
var currentKey = keys[index];
results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
}
return results;
};
// 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 keys = _.keys(obj); var keys = _.keys(obj);
var length = keys.length; var length = keys.length;
var pairs = Array(length); var pairs = Array(length);
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
pairs[i] = [keys[i], obj[keys[i]]]; pairs[i] = [keys[i], obj[keys[i]]];
} }
return pairs; return pairs;
}; };
skipping to change at line 898 skipping to change at line 1039
// Return a sorted list of the function names available on the object. // Return a sorted list of the function names available on the object.
// Aliased as `methods` // Aliased as `methods`
_.functions = _.methods = function(obj) { _.functions = _.methods = function(obj) {
var names = []; var names = [];
for (var key in obj) { for (var key in obj) {
if (_.isFunction(obj[key])) names.push(key); if (_.isFunction(obj[key])) names.push(key);
} }
return names.sort(); return names.sort();
}; };
// Extend a given object with all the properties in passed-in object(s). // An internal function for creating assigner functions.
_.extend = function(obj) { var createAssigner = function(keysFunc, defaults) {
if (!_.isObject(obj)) return obj; return function(obj) {
var source, prop; var length = arguments.length;
for (var i = 1, length = arguments.length; i < length; i++) { if (defaults) obj = Object(obj);
source = arguments[i]; if (length < 2 || obj == null) return obj;
for (prop in source) { for (var index = 1; index < length; index++) {
if (hasOwnProperty.call(source, prop)) { var source = arguments[index],
obj[prop] = source[prop]; keys = keysFunc(source),
l = keys.length;
for (var i = 0; i < l; i++) {
var key = keys[i];
if (!defaults || obj[key] === void 0) obj[key] = source[key];
} }
} }
return obj;
};
};
// Extend a given object with all the properties in passed-in object(s).
_.extend = createAssigner(_.allKeys);
// Assigns a given object with all the own properties in the passed-in object(
s)
// (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects
/Object/assign)
_.extendOwn = _.assign = createAssigner(_.keys);
// Returns the first key on an object that passes a predicate test
_.findKey = function(obj, predicate, context) {
predicate = cb(predicate, context);
var keys = _.keys(obj), key;
for (var i = 0, length = keys.length; i < length; i++) {
key = keys[i];
if (predicate(obj[key], key, obj)) return key;
} }
return obj; };
// Internal pick helper function to determine if `obj` has key `key`.
var keyInObj = function(value, key, obj) {
return key in obj;
}; };
// Return a copy of the object only containing the whitelisted properties. // Return a copy of the object only containing the whitelisted properties.
_.pick = function(obj, iteratee, context) { _.pick = restArgs(function(obj, keys) {
var result = {}, key; var result = {}, iteratee = keys[0];
if (obj == null) return result; if (obj == null) return result;
if (_.isFunction(iteratee)) { if (_.isFunction(iteratee)) {
iteratee = createCallback(iteratee, context); if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]);
for (key in obj) { keys = _.allKeys(obj);
var value = obj[key];
if (iteratee(value, key, obj)) result[key] = value;
}
} else { } else {
var keys = concat.apply([], slice.call(arguments, 1)); iteratee = keyInObj;
obj = new Object(obj); keys = flatten(keys, false, false);
for (var i = 0, length = keys.length; i < length; i++) { obj = Object(obj);
key = keys[i]; }
if (key in obj) result[key] = obj[key]; for (var i = 0, length = keys.length; i < length; i++) {
} var key = keys[i];
var value = obj[key];
if (iteratee(value, key, obj)) result[key] = value;
} }
return result; return result;
}; });
// Return a copy of the object without the blacklisted properties. // Return a copy of the object without the blacklisted properties.
_.omit = function(obj, iteratee, context) { _.omit = restArgs(function(obj, keys) {
var iteratee = keys[0], context;
if (_.isFunction(iteratee)) { if (_.isFunction(iteratee)) {
iteratee = _.negate(iteratee); iteratee = _.negate(iteratee);
if (keys.length > 1) context = keys[1];
} else { } else {
var keys = _.map(concat.apply([], slice.call(arguments, 1)), String); keys = _.map(flatten(keys, false, false), String);
iteratee = function(value, key) { iteratee = function(value, key) {
return !_.contains(keys, key); return !_.contains(keys, key);
}; };
} }
return _.pick(obj, iteratee, context); return _.pick(obj, iteratee, context);
}; });
// Fill in a given object with default properties. // Fill in a given object with default properties.
_.defaults = function(obj) { _.defaults = createAssigner(_.allKeys, true);
if (!_.isObject(obj)) return obj;
for (var i = 1, length = arguments.length; i < length; i++) { // Creates an object that inherits from the given prototype object.
var source = arguments[i]; // If additional properties are provided then they will be added to the
for (var prop in source) { // created object.
if (obj[prop] === void 0) obj[prop] = source[prop]; _.create = function(prototype, props) {
} var result = baseCreate(prototype);
} if (props) _.extendOwn(result, props);
return obj; return result;
}; };
// Create a (shallow-cloned) duplicate of an object. // Create a (shallow-cloned) duplicate of an object.
_.clone = function(obj) { _.clone = function(obj) {
if (!_.isObject(obj)) return obj; if (!_.isObject(obj)) return obj;
return _.isArray(obj) ? obj.slice() : _.extend({}, obj); return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
}; };
// Invokes interceptor with the obj, and then returns obj. // Invokes interceptor with the obj, and then returns obj.
// The primary purpose of this method is to "tap into" a method chain, in // The primary purpose of this method is to "tap into" a method chain, in
// order to perform operations on intermediate results within the chain. // order to perform operations on intermediate results within the chain.
_.tap = function(obj, interceptor) { _.tap = function(obj, interceptor) {
interceptor(obj); interceptor(obj);
return obj; return obj;
}; };
// Returns whether an object has a given set of `key:value` pairs.
_.isMatch = function(object, attrs) {
var keys = _.keys(attrs), length = keys.length;
if (object == null) return !length;
var obj = Object(object);
for (var i = 0; i < length; i++) {
var key = keys[i];
if (attrs[key] !== obj[key] || !(key in obj)) return false;
}
return true;
};
// Internal recursive comparison function for `isEqual`. // Internal recursive comparison function for `isEqual`.
var eq = function(a, b, aStack, bStack) { var eq, deepEq;
eq = function(a, b, aStack, bStack) {
// Identical objects are equal. `0 === -0`, but they aren't identical. // Identical objects are equal. `0 === -0`, but they aren't identical.
// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id= harmony:egal). // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id= harmony:egal).
if (a === b) return a !== 0 || 1 / a === 1 / b; if (a === b) return a !== 0 || 1 / a === 1 / b;
// A strict comparison is necessary because `null == undefined`. // A strict comparison is necessary because `null == undefined`.
if (a == null || b == null) return a === b; if (a == null || b == null) return a === b;
// `NaN`s are equivalent, but non-reflexive.
if (a !== a) return b !== b;
// Exhaust primitive checks
var type = typeof a;
if (type !== 'function' && type !== 'object' && typeof b != 'object') return
false;
return deepEq(a, b, aStack, bStack);
};
// Internal recursive comparison function for `isEqual`.
deepEq = function(a, b, aStack, bStack) {
// Unwrap any wrapped objects. // Unwrap any wrapped objects.
if (a instanceof _) a = a._wrapped; if (a instanceof _) a = a._wrapped;
if (b instanceof _) b = b._wrapped; if (b instanceof _) b = b._wrapped;
// Compare `[[Class]]` names. // Compare `[[Class]]` names.
var className = toString.call(a); var className = toString.call(a);
if (className !== toString.call(b)) return false; if (className !== toString.call(b)) return false;
switch (className) { switch (className) {
// Strings, numbers, regular expressions, dates, and booleans are compared by value. // Strings, numbers, regular expressions, dates, and booleans are compared by value.
case '[object RegExp]': case '[object RegExp]':
// RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/ i') // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/ i')
skipping to change at line 1007 skipping to change at line 1198
if (+a !== +a) return +b !== +b; if (+a !== +a) return +b !== +b;
// An `egal` comparison is performed for other numeric values. // An `egal` comparison is performed for other numeric values.
return +a === 0 ? 1 / +a === 1 / b : +a === +b; return +a === 0 ? 1 / +a === 1 / b : +a === +b;
case '[object Date]': case '[object Date]':
case '[object Boolean]': case '[object Boolean]':
// Coerce dates and booleans to numeric primitive values. Dates are comp ared by their // Coerce dates and booleans to numeric primitive values. Dates are comp ared by their
// millisecond representations. Note that invalid dates with millisecond representations // millisecond representations. Note that invalid dates with millisecond representations
// of `NaN` are not equivalent. // of `NaN` are not equivalent.
return +a === +b; return +a === +b;
} }
if (typeof a != 'object' || typeof b != 'object') return false;
var areArrays = className === '[object Array]';
if (!areArrays) {
if (typeof a != 'object' || typeof b != 'object') return false;
// Objects with different constructors are not equivalent, but `Object`s o
r `Array`s
// from different frames are.
var aCtor = a.constructor, bCtor = b.constructor;
if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
_.isFunction(bCtor) && bCtor instanceof bCtor)
&& ('constructor' in a && 'constructor' in b)) {
return false;
}
}
// Assume equality for cyclic structures. The algorithm for detecting cyclic // Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO `. // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO `.
// Initializing stack of traversed objects.
// It's done here since we only need them for objects and arrays comparison.
aStack = aStack || [];
bStack = bStack || [];
var length = aStack.length; var length = aStack.length;
while (length--) { while (length--) {
// Linear search. Performance is inversely proportional to the number of // Linear search. Performance is inversely proportional to the number of
// unique nested structures. // unique nested structures.
if (aStack[length] === a) return bStack[length] === b; if (aStack[length] === a) return bStack[length] === b;
} }
// Objects with different constructors are not equivalent, but `Object`s
// from different frames are.
var aCtor = a.constructor, bCtor = b.constructor;
if (
aCtor !== bCtor &&
// Handle Object.create(x) cases
'constructor' in a && 'constructor' in b &&
!(_.isFunction(aCtor) && aCtor instanceof aCtor &&
_.isFunction(bCtor) && bCtor instanceof bCtor)
) {
return false;
}
// Add the first object to the stack of traversed objects. // Add the first object to the stack of traversed objects.
aStack.push(a); aStack.push(a);
bStack.push(b); bStack.push(b);
var size, result;
// Recursively compare objects and arrays. // Recursively compare objects and arrays.
if (className === '[object Array]') { if (areArrays) {
// Compare array lengths to determine if a deep comparison is necessary. // Compare array lengths to determine if a deep comparison is necessary.
size = a.length; length = a.length;
result = size === b.length; if (length !== b.length) return false;
if (result) { // Deep compare the contents, ignoring non-numeric properties.
// Deep compare the contents, ignoring non-numeric properties. while (length--) {
while (size--) { if (!eq(a[length], b[length], aStack, bStack)) return false;
if (!(result = eq(a[size], b[size], aStack, bStack))) break;
}
} }
} else { } else {
// Deep compare objects. // Deep compare objects.
var keys = _.keys(a), key; var keys = _.keys(a), key;
size = keys.length; length = keys.length;
// Ensure that both objects contain the same number of properties before c omparing deep equality. // Ensure that both objects contain the same number of properties before c omparing deep equality.
result = _.keys(b).length === size; if (_.keys(b).length !== length) return false;
if (result) { while (length--) {
while (size--) { // Deep compare each member
// Deep compare each member key = keys[length];
key = keys[size]; if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false
if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) b ;
reak;
}
} }
} }
// Remove the first object from the stack of traversed objects. // Remove the first object from the stack of traversed objects.
aStack.pop(); aStack.pop();
bStack.pop(); bStack.pop();
return result; return true;
}; };
// Perform a deep comparison to check if two objects are equal. // Perform a deep comparison to check if two objects are equal.
_.isEqual = function(a, b) { _.isEqual = function(a, b) {
return eq(a, b, [], []); return eq(a, b);
}; };
// Is a given array, string, or object empty? // Is a given array, string, or object empty?
// An "empty" object has no enumerable own-properties. // An "empty" object has no enumerable own-properties.
_.isEmpty = function(obj) { _.isEmpty = function(obj) {
if (obj == null) return true; if (obj == null) return true;
if (_.isArray(obj) || _.isString(obj) || _.isArguments(obj)) return obj.leng if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(
th === 0; obj))) return obj.length === 0;
for (var key in obj) if (_.has(obj, key)) return false; return _.keys(obj).length === 0;
return true;
}; };
// Is a given value a DOM element? // Is a given value a DOM element?
_.isElement = function(obj) { _.isElement = function(obj) {
return !!(obj && obj.nodeType === 1); return !!(obj && obj.nodeType === 1);
}; };
// Is a given value an array? // Is a given value an array?
// Delegates to ECMA5's native Array.isArray // Delegates to ECMA5's native Array.isArray
_.isArray = nativeIsArray || function(obj) { _.isArray = nativeIsArray || function(obj) {
return toString.call(obj) === '[object Array]'; return toString.call(obj) === '[object Array]';
}; };
// Is a given variable an object? // Is a given variable an object?
_.isObject = function(obj) { _.isObject = function(obj) {
var type = typeof obj; var type = typeof obj;
return type === 'function' || type === 'object' && !!obj; return type === 'function' || type === 'object' && !!obj;
}; };
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDat // Add some isType methods: isArguments, isFunction, isString, isNumber, isDat
e, isRegExp. e, isRegExp, isError.
_.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], functi _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'
on(name) { ], function(name) {
_['is' + name] = function(obj) { _['is' + name] = function(obj) {
return toString.call(obj) === '[object ' + name + ']'; return toString.call(obj) === '[object ' + name + ']';
}; };
}); });
// Define a fallback version of the method in browsers (ahem, IE), where // Define a fallback version of the method in browsers (ahem, IE < 9), where
// there isn't any inspectable "Arguments" type. // there isn't any inspectable "Arguments" type.
if (!_.isArguments(arguments)) { if (!_.isArguments(arguments)) {
_.isArguments = function(obj) { _.isArguments = function(obj) {
return _.has(obj, 'callee'); return _.has(obj, 'callee');
}; };
} }
// Optimize `isFunction` if appropriate. Work around an IE 11 bug. // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v
if (typeof /./ !== 'function') { 8,
// IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236).
var nodelist = root.document && root.document.childNodes;
if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelis
t != 'function') {
_.isFunction = function(obj) { _.isFunction = function(obj) {
return typeof obj == 'function' || false; return typeof obj == 'function' || false;
}; };
} }
// Is a given object a finite number? // Is a given object a finite number?
_.isFinite = function(obj) { _.isFinite = function(obj) {
return isFinite(obj) && !isNaN(parseFloat(obj)); return isFinite(obj) && !isNaN(parseFloat(obj));
}; };
// Is the given value `NaN`? (NaN is the only number which does not equal itse lf). // Is the given value `NaN`?
_.isNaN = function(obj) { _.isNaN = function(obj) {
return _.isNumber(obj) && obj !== +obj; return _.isNumber(obj) && isNaN(obj);
}; };
// Is a given value a boolean? // Is a given value a boolean?
_.isBoolean = function(obj) { _.isBoolean = function(obj) {
return obj === true || obj === false || toString.call(obj) === '[object Bool ean]'; return obj === true || obj === false || toString.call(obj) === '[object Bool ean]';
}; };
// Is a given value equal to null? // Is a given value equal to null?
_.isNull = function(obj) { _.isNull = function(obj) {
return obj === null; return obj === null;
skipping to change at line 1162 skipping to change at line 1357
_.noConflict = function() { _.noConflict = function() {
root._ = previousUnderscore; root._ = previousUnderscore;
return this; return this;
}; };
// Keep the identity function around for default iteratees. // Keep the identity function around for default iteratees.
_.identity = function(value) { _.identity = function(value) {
return value; return value;
}; };
// Predicate-generating functions. Often useful outside of Underscore.
_.constant = function(value) { _.constant = function(value) {
return function() { return function() {
return value; return value;
}; };
}; };
_.noop = function(){}; _.noop = function(){};
_.property = function(key) { _.property = property;
return function(obj) {
// Generates a function for a given object that returns a given property.
_.propertyOf = function(obj) {
return obj == null ? function(){} : function(key) {
return obj[key]; return obj[key];
}; };
}; };
// Returns a predicate for checking whether an object has a given set of `key: // Returns a predicate for checking whether an object has a given set of
value` pairs. // `key:value` pairs.
_.matches = function(attrs) { _.matcher = _.matches = function(attrs) {
var pairs = _.pairs(attrs), length = pairs.length; attrs = _.extendOwn({}, attrs);
return function(obj) { return function(obj) {
if (obj == null) return !length; return _.isMatch(obj, attrs);
obj = new Object(obj);
for (var i = 0; i < length; i++) {
var pair = pairs[i], key = pair[0];
if (pair[1] !== obj[key] || !(key in obj)) return false;
}
return true;
}; };
}; };
// Run a function **n** times. // Run a function **n** times.
_.times = function(n, iteratee, context) { _.times = function(n, iteratee, context) {
var accum = Array(Math.max(0, n)); var accum = Array(Math.max(0, n));
iteratee = createCallback(iteratee, context, 1); iteratee = optimizeCb(iteratee, context, 1);
for (var i = 0; i < n; i++) accum[i] = iteratee(i); for (var i = 0; i < n; i++) accum[i] = iteratee(i);
return accum; return accum;
}; };
// Return a random integer between min and max (inclusive). // Return a random integer between min and max (inclusive).
_.random = function(min, max) { _.random = function(min, max) {
if (max == null) { if (max == null) {
max = min; max = min;
min = 0; min = 0;
} }
skipping to change at line 1242 skipping to change at line 1436
return function(string) { return function(string) {
string = string == null ? '' : '' + string; string = string == null ? '' : '' + string;
return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
}; };
}; };
_.escape = createEscaper(escapeMap); _.escape = createEscaper(escapeMap);
_.unescape = createEscaper(unescapeMap); _.unescape = createEscaper(unescapeMap);
// If the value of the named `property` is a function then invoke it with the // If the value of the named `property` is a function then invoke it with the
// `object` as context; otherwise, return it. // `object` as context; otherwise, return it.
_.result = function(object, property) { _.result = function(object, prop, fallback) {
if (object == null) return void 0; var value = object == null ? void 0 : object[prop];
var value = object[property]; if (value === void 0) {
return _.isFunction(value) ? object[property]() : value; value = fallback;
}
return _.isFunction(value) ? value.call(object) : value;
}; };
// Generate a unique integer id (unique within the entire client session). // Generate a unique integer id (unique within the entire client session).
// Useful for temporary DOM ids. // Useful for temporary DOM ids.
var idCounter = 0; var idCounter = 0;
_.uniqueId = function(prefix) { _.uniqueId = function(prefix) {
var id = ++idCounter + ''; var id = ++idCounter + '';
return prefix ? prefix + id : id; return prefix ? prefix + id : id;
}; };
// By default, Underscore uses ERB-style template delimiters, change the // By default, Underscore uses ERB-style template delimiters, change the
// following template settings to use alternative delimiters. // following template settings to use alternative delimiters.
_.templateSettings = { _.templateSettings = {
evaluate : /<%([\s\S]+?)%>/g, evaluate: /<%([\s\S]+?)%>/g,
interpolate : /<%=([\s\S]+?)%>/g, interpolate: /<%=([\s\S]+?)%>/g,
escape : /<%-([\s\S]+?)%>/g escape: /<%-([\s\S]+?)%>/g
}; };
// When customizing `templateSettings`, if you don't want to define an // When customizing `templateSettings`, if you don't want to define an
// interpolation, evaluation or escaping regex, we need one that is // interpolation, evaluation or escaping regex, we need one that is
// guaranteed not to match. // guaranteed not to match.
var noMatch = /(.)^/; var noMatch = /(.)^/;
// Certain characters need to be escaped so that they can be put into a // Certain characters need to be escaped so that they can be put into a
// string literal. // string literal.
var escapes = { var escapes = {
"'": "'", "'": "'",
'\\': '\\', '\\': '\\',
'\r': 'r', '\r': 'r',
'\n': 'n', '\n': 'n',
'\u2028': 'u2028', '\u2028': 'u2028',
'\u2029': 'u2029' '\u2029': 'u2029'
}; };
var escaper = /\\|'|\r|\n|\u2028|\u2029/g; var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g;
var escapeChar = function(match) { var escapeChar = function(match) {
return '\\' + escapes[match]; return '\\' + escapes[match];
}; };
// JavaScript micro-templating, similar to John Resig's implementation. // JavaScript micro-templating, similar to John Resig's implementation.
// Underscore templating handles arbitrary delimiters, preserves whitespace, // Underscore templating handles arbitrary delimiters, preserves whitespace,
// and correctly escapes quotes within interpolated code. // and correctly escapes quotes within interpolated code.
// NB: `oldSettings` only exists for backwards compatibility. // NB: `oldSettings` only exists for backwards compatibility.
_.template = function(text, settings, oldSettings) { _.template = function(text, settings, oldSettings) {
skipping to change at line 1305 skipping to change at line 1501
var matcher = RegExp([ var matcher = RegExp([
(settings.escape || noMatch).source, (settings.escape || noMatch).source,
(settings.interpolate || noMatch).source, (settings.interpolate || noMatch).source,
(settings.evaluate || noMatch).source (settings.evaluate || noMatch).source
].join('|') + '|$', 'g'); ].join('|') + '|$', 'g');
// Compile the template source, escaping string literals appropriately. // Compile the template source, escaping string literals appropriately.
var index = 0; var index = 0;
var source = "__p+='"; var source = "__p+='";
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
source += text.slice(index, offset).replace(escaper, escapeChar); source += text.slice(index, offset).replace(escapeRegExp, escapeChar);
index = offset + match.length; index = offset + match.length;
if (escape) { if (escape) {
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
} else if (interpolate) { } else if (interpolate) {
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
} else if (evaluate) { } else if (evaluate) {
source += "';\n" + evaluate + "\n__p+='"; source += "';\n" + evaluate + "\n__p+='";
} }
// Adobe VMs need the match returned to produce the correct offest. // Adobe VMs need the match returned to produce the correct offset.
return match; return match;
}); });
source += "';\n"; source += "';\n";
// If a variable is not specified, place data values in local scope. // If a variable is not specified, place data values in local scope.
if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
source = "var __t,__p='',__j=Array.prototype.join," + source = "var __t,__p='',__j=Array.prototype.join," +
"print=function(){__p+=__j.call(arguments,'');};\n" + "print=function(){__p+=__j.call(arguments,'');};\n" +
source + 'return __p;\n'; source + 'return __p;\n';
var render;
try { try {
var render = new Function(settings.variable || 'obj', '_', source); render = new Function(settings.variable || 'obj', '_', source);
} catch (e) { } catch (e) {
e.source = source; e.source = source;
throw e; throw e;
} }
var template = function(data) { var template = function(data) {
return render.call(this, data, _); return render.call(this, data, _);
}; };
// Provide the compiled source as a convenience for precompilation. // Provide the compiled source as a convenience for precompilation.
skipping to change at line 1360 skipping to change at line 1557
return instance; return instance;
}; };
// OOP // OOP
// --------------- // ---------------
// If Underscore is called as a function, it returns a wrapped object that // If Underscore is called as a function, it returns a wrapped object that
// can be used OO-style. This wrapper holds altered versions of all the // can be used OO-style. This wrapper holds altered versions of all the
// underscore functions. Wrapped objects may be chained. // underscore functions. Wrapped objects may be chained.
// Helper function to continue chaining intermediate results. // Helper function to continue chaining intermediate results.
var result = function(obj) { var chainResult = function(instance, obj) {
return this._chain ? _(obj).chain() : obj; return instance._chain ? _(obj).chain() : obj;
}; };
// 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];
push.apply(args, arguments); push.apply(args, arguments);
return result.call(this, func.apply(_, args)); return chainResult(this, func.apply(_, args));
}; };
}); });
}; };
// Add all of the Underscore functions to the wrapper object. // Add all of the Underscore functions to the wrapper object.
_.mixin(_); _.mixin(_);
// Add all mutator Array functions to the wrapper. // Add all mutator Array functions to the wrapper.
_.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], funct ion(name) { _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], funct ion(name) {
var method = ArrayProto[name]; var method = ArrayProto[name];
_.prototype[name] = function() { _.prototype[name] = function() {
var obj = this._wrapped; var obj = this._wrapped;
method.apply(obj, arguments); method.apply(obj, arguments);
if ((name === 'shift' || name === 'splice') && obj.length === 0) delete ob j[0]; if ((name === 'shift' || name === 'splice') && obj.length === 0) delete ob j[0];
return result.call(this, obj); return chainResult(this, obj);
}; };
}); });
// Add all accessor Array functions to the wrapper. // Add all accessor Array functions to the wrapper.
_.each(['concat', 'join', 'slice'], function(name) { _.each(['concat', 'join', 'slice'], function(name) {
var method = ArrayProto[name]; var method = ArrayProto[name];
_.prototype[name] = function() { _.prototype[name] = function() {
return result.call(this, method.apply(this._wrapped, arguments)); return chainResult(this, method.apply(this._wrapped, arguments));
}; };
}); });
// Extracts the result from a wrapped and chained object. // Extracts the result from a wrapped and chained object.
_.prototype.value = function() { _.prototype.value = function() {
return this._wrapped; return this._wrapped;
}; };
// Provide unwrapping proxy for some methods used in engine operations
// such as arithmetic and JSON stringification.
_.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
_.prototype.toString = function() {
return '' + this._wrapped;
};
// AMD registration happens at the end for compatibility with AMD loaders // AMD registration happens at the end for compatibility with AMD loaders
// that may not enforce next-turn semantics on modules. Even though general // that may not enforce next-turn semantics on modules. Even though general
// practice for AMD registration is to be anonymous, underscore registers // practice for AMD registration is to be anonymous, underscore registers
// as a named module because, like jQuery, it is a base library that is // as a named module because, like jQuery, it is a base library that is
// popular enough to be bundled in a third party lib, but not be part of // popular enough to be bundled in a third party lib, but not be part of
// an AMD load request. Those cases could generate an error when an // an AMD load request. Those cases could generate an error when an
// anonymous define() is called outside of a loader request. // anonymous define() is called outside of a loader request.
if (typeof define === 'function' && define.amd) { if (typeof define == 'function' && define.amd) {
define('underscore', [], function() { define('underscore', [], function() {
return _; return _;
}); });
} }
}.call(this)); }());
 End of changes. 168 change blocks. 
438 lines changed or deleted 656 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)