-(function() {
diff --git a/bower.json b/bower.json index 2d3e0291c..82acb5c77 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "underscore", - "version": "1.6.0", + "version": "1.7.0", "main": "underscore.js", "keywords": ["util", "functional", "server", "client", "browser"], "ignore" : ["docs", "test", "*.yml", "CNAME", "index.html", "favicon.ico", "CONTRIBUTING.md"] diff --git a/component.json b/component.json index bb1775e70..47d145086 100644 --- a/component.json +++ b/component.json @@ -5,6 +5,6 @@ "repo" : "jashkenas/underscore", "main" : "underscore.js", "scripts" : ["underscore.js"], - "version" : "1.6.0", + "version" : "1.7.0", "license" : "MIT" } diff --git a/docs/underscore.html b/docs/underscore.html index 014d5dece..9ac964368 100644 --- a/docs/underscore.html +++ b/docs/underscore.html @@ -27,7 +27,7 @@
Underscore.js 1.6.0
+ Underscore.js 1.7.0
http://underscorejs.org
(c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
Underscore may be freely distributed under the MIT license.
@@ -35,7 +35,7 @@ underscore.js
-(function() {
+(function() {
@@ -101,21 +101,6 @@ Baseline setup
- Establish the object that gets returned to break out of a loop iteration.
-
-
-
- var breaker = {};
-
-
-
-
-
-
-
-
- ¶
-
Save bytes in the minified (but not gzipped) version:
@@ -125,11 +110,11 @@ Baseline setup
-
+
Create quick reference variables for speed access to core prototypes.
@@ -145,11 +130,11 @@ Baseline setup
-
+
All ECMAScript 5 native function implementations that we hope to use
are declared here.
@@ -157,15 +142,6 @@ Baseline setup
var
- nativeForEach = ArrayProto.forEach,
- nativeMap = ArrayProto.map,
- nativeReduce = ArrayProto.reduce,
- nativeReduceRight = ArrayProto.reduceRight,
- nativeFilter = ArrayProto.filter,
- nativeEvery = ArrayProto.every,
- nativeSome = ArrayProto.some,
- nativeIndexOf = ArrayProto.indexOf,
- nativeLastIndexOf = ArrayProto.lastIndexOf,
nativeIsArray = Array.isArray,
nativeKeys = Object.keys,
nativeBind = FuncProto.bind;
@@ -173,17 +149,17 @@ Baseline setup
-
+
- var _ = function(obj) {
+ var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);
this._wrapped = obj;
@@ -192,22 +168,21 @@ Baseline setup
-
+
Export the Underscore object for Node.js, with
backwards-compatibility for the old require()
API. If we’re in
-the browser, add _
as a global object via a string identifier,
-for Closure Compiler “advanced” mode.
+the browser, add _
as a global object.
if (typeof exports !== 'undefined') {
- if (typeof module !== 'undefined' && module.exports) {
- exports = module.exports = _;
+ if (typeof module !== 'undefined' && module.exports) {
+ exports = module.exports = _;
}
exports._ = _;
} else {
@@ -217,11 +192,11 @@ Baseline setup
-
+
Current version.
@@ -232,16 +207,61 @@ Baseline setup
+
+
+
+
+ ¶
+
+ Internal function that returns an efficient (for current engines) version
+of the passed-in callback, to be repeatedly applied in other Underscore
+functions.
+
+
+
+ var createCallback = function(func, context, argCount) {
+ if (context === void 0) return func;
+ switch (argCount == null ? 3 : argCount) {
+ case 1: return function(value) {
+ return func.call(context, value);
+ };
+ case 2: return function(value, other) {
+ return func.call(context, value, other);
+ };
+ case 3: return function(value, index, collection) {
+ return func.call(context, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(context, accumulator, value, index, collection);
+ };
+ }
+ return function() {
+ return func.apply(context, arguments);
+ };
+ };
+
+
+
+
- Collection Functions
+ A mostly-internal function to generate callbacks that can be applied
+to each element in a collection, returning the desired result — either
+identity, an arbitrary callback, a property matcher, or a property accessor.
+ _.iteratee = function(value, context, argCount) {
+ if (value == null) return _.identity;
+ if (_.isFunction(value)) return createCallback(value, context, argCount);
+ if (_.isObject(value)) return _.matches(value);
+ return _.property(value);
+ };
+
@@ -251,7 +271,8 @@ Collection Functions
-
+ Collection Functions
+
@@ -263,24 +284,36 @@ Collection Functions
+
+
+
+
+
+
+
+
+
+
+ ¶
+
The cornerstone, an each
implementation, aka forEach
.
-Handles objects with the built-in forEach
, arrays, and raw objects.
-Delegates to ECMAScript 5‘s native forEach
if available.
+Handles raw objects in addition to array-likes. Treats all
+sparse array-likes as if they were dense.
- var each = _.each = _.forEach = function(obj, iterator, context) {
+ _.each = _.forEach = function(obj, iteratee, context) {
if (obj == null) return obj;
- if (nativeForEach && obj.forEach === nativeForEach) {
- obj.forEach(iterator, context);
- } else if (obj.length === +obj.length) {
- for (var i = 0, length = obj.length; i < length; i++) {
- if (iterator.call(context, obj[i], i, obj) === breaker) return;
+ iteratee = createCallback(iteratee, context);
+ var i, length = obj.length;
+ if (length === +length) {
+ for (i = 0; i < length; i++) {
+ iteratee(obj[i], i, obj);
}
} else {
var keys = _.keys(obj);
- for (var i = 0, length = keys.length; i < length; i++) {
- if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
+ for (i = 0, length = keys.length; i < length; i++) {
+ iteratee(obj[keys[i]], keys[i], obj);
}
}
return obj;
@@ -289,24 +322,27 @@ Collection Functions
-
+
- Return the results of applying the iterator to each element.
-Delegates to ECMAScript 5‘s native map
if available.
+ Return the results of applying the iteratee to each element.
- _.map = _.collect = function(obj, iterator, context) {
- var results = [];
- if (obj == null) return results;
- if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
- each(obj, function(value, index, list) {
- results.push(iterator.call(context, value, index, list));
- });
+ _.map = _.collect = function(obj, iteratee, context) {
+ if (obj == null) return [];
+ iteratee = _.iteratee(iteratee, context);
+ var keys = obj.length !== +obj.length && _.keys(obj),
+ length = (keys || obj).length,
+ results = Array(length),
+ currentKey;
+ for (var index = 0; index < length; index++) {
+ currentKey = keys ? keys[index] : index;
+ results[index] = iteratee(obj[currentKey], currentKey, obj);
+ }
return results;
};
@@ -315,92 +351,82 @@ Collection Functions
-
+
Reduce builds up a single result from a list of values, aka inject
,
-or foldl
. Delegates to ECMAScript 5‘s native reduce
if available.
+or foldl
.
- _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
- var initial = arguments.length > 2;
+ _.reduce = _.foldl = _.inject = function(obj, iteratee, memo, context) {
if (obj == null) obj = [];
- if (nativeReduce && obj.reduce === nativeReduce) {
- if (context) iterator = _.bind(iterator, context);
- return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
+ 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);
}
- each(obj, function(value, index, list) {
- if (!initial) {
- memo = value;
- initial = true;
- } else {
- memo = iterator.call(context, memo, value, index, list);
- }
- });
- if (!initial) throw new TypeError(reduceError);
return memo;
};
-
+
- The right-associative version of reduce, also known as foldr
.
-Delegates to ECMAScript 5‘s native reduceRight
if available.
+ The right-associative version of reduce, also known as foldr
.
- _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
- var initial = arguments.length > 2;
+ _.reduceRight = _.foldr = function(obj, iteratee, memo, context) {
if (obj == null) obj = [];
- if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
- if (context) iterator = _.bind(iterator, context);
- return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
+ 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];
}
- var length = obj.length;
- if (length !== +length) {
- var keys = _.keys(obj);
- length = keys.length;
+ while (index--) {
+ currentKey = keys ? keys[index] : index;
+ memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
- each(obj, function(value, index, list) {
- index = keys ? keys[--length] : --length;
- if (!initial) {
- memo = obj[index];
- initial = true;
- } else {
- memo = iterator.call(context, memo, obj[index], index, list);
- }
- });
- if (!initial) throw new TypeError(reduceError);
return memo;
};
-
+
- _.find = _.detect = function(obj, predicate, context) {
+ _.find = _.detect = function(obj, predicate, context) {
var result;
- any(obj, function(value, index, list) {
- if (predicate.call(context, value, index, list)) {
+ predicate = _.iteratee(predicate, context);
+ _.some(obj, function(value, index, list) {
+ if (predicate(value, index, list)) {
result = value;
return true;
}
@@ -411,24 +437,23 @@ Collection Functions
-
+
Return all the elements that pass a truth test.
-Delegates to ECMAScript 5‘s native filter
if available.
Aliased as select
.
- _.filter = _.select = function(obj, predicate, context) {
+ _.filter = _.select = function(obj, predicate, context) {
var results = [];
if (obj == null) return results;
- if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context);
- each(obj, function(value, index, list) {
- if (predicate.call(context, value, index, list)) results.push(value);
+ predicate = _.iteratee(predicate, context);
+ _.each(obj, function(value, index, list) {
+ if (predicate(value, index, list)) results.push(value);
});
return results;
};
@@ -436,113 +461,111 @@ Collection Functions
-
+
- _.reject = function(obj, predicate, context) {
- return _.filter(obj, function(value, index, list) {
- return !predicate.call(context, value, index, list);
- }, context);
+ _.reject = function(obj, predicate, context) {
+ return _.filter(obj, _.negate(_.iteratee(predicate)), context);
};
-
+
Determine whether all of the elements match a truth test.
-Delegates to ECMAScript 5‘s native every
if available.
Aliased as all
.
- _.every = _.all = function(obj, predicate, context) {
- predicate || (predicate = _.identity);
- var result = true;
- if (obj == null) return result;
- if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context);
- each(obj, function(value, index, list) {
- if (!(result = result && predicate.call(context, value, index, list))) return breaker;
- });
- return !!result;
+ _.every = _.all = function(obj, predicate, context) {
+ if (obj == null) return true;
+ predicate = _.iteratee(predicate, context);
+ var keys = obj.length !== +obj.length && _.keys(obj),
+ length = (keys || obj).length,
+ index, currentKey;
+ for (index = 0; index < length; index++) {
+ currentKey = keys ? keys[index] : index;
+ if (!predicate(obj[currentKey], currentKey, obj)) return false;
+ }
+ return true;
};
-
+
Determine if at least one element in the object matches a truth test.
-Delegates to ECMAScript 5‘s native some
if available.
Aliased as any
.
- var any = _.some = _.any = function(obj, predicate, context) {
- predicate || (predicate = _.identity);
- var result = false;
- if (obj == null) return result;
- if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context);
- each(obj, function(value, index, list) {
- if (result || (result = predicate.call(context, value, index, list))) return breaker;
- });
- return !!result;
+ _.some = _.any = function(obj, predicate, context) {
+ if (obj == null) return false;
+ predicate = _.iteratee(predicate, context);
+ var keys = obj.length !== +obj.length && _.keys(obj),
+ length = (keys || obj).length,
+ index, currentKey;
+ for (index = 0; index < length; index++) {
+ currentKey = keys ? keys[index] : index;
+ if (predicate(obj[currentKey], currentKey, obj)) return true;
+ }
+ return false;
};
-
+
- _.contains = _.include = function(obj, target) {
+ _.contains = _.include = function(obj, target) {
if (obj == null) return false;
- if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
- return any(obj, function(value) {
- return value === target;
- });
+ if (obj.length !== +obj.length) obj = _.values(obj);
+ return _.indexOf(obj, target) >= 0;
};
-
+
- _.invoke = function(obj, method) {
+ _.invoke = function(obj, method) {
var args = slice.call(arguments, 2);
var isFunc = _.isFunction(method);
- return _.map(obj, function(value) {
+ return _.map(obj, function(value) {
return (isFunc ? method : value[method]).apply(value, args);
});
};
@@ -550,148 +573,164 @@ Collection Functions
-
+
- _.pluck = function(obj, key) {
+ _.pluck = function(obj, key) {
return _.map(obj, _.property(key));
};
-
+
Convenience version of a common use case of filter
: selecting only objects
containing specific key:value
pairs.
- _.where = function(obj, attrs) {
+ _.where = function(obj, attrs) {
return _.filter(obj, _.matches(attrs));
};
-
+
Convenience version of a common use case of find
: getting the first object
containing specific key:value
pairs.
- _.findWhere = function(obj, attrs) {
+ _.findWhere = function(obj, attrs) {
return _.find(obj, _.matches(attrs));
};
-
+
- Return the maximum element or (element-based computation).
-Can’t optimize arrays of integers longer than 65,535 elements.
-See WebKit Bug 80797
+ Return the maximum element (or element-based computation).
- _.max = function(obj, iterator, context) {
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
- return Math.max.apply(Math, obj);
- }
- var result = -Infinity, lastComputed = -Infinity;
- each(obj, function(value, index, list) {
- var computed = iterator ? iterator.call(context, value, index, list) : value;
- if (computed > lastComputed) {
- result = value;
- lastComputed = computed;
+ _.max = function(obj, iteratee, context) {
+ var result = -Infinity, lastComputed = -Infinity,
+ value, computed;
+ if (iteratee == null && obj != null) {
+ obj = obj.length === +obj.length ? obj : _.values(obj);
+ for (var i = 0, length = obj.length; i < length; i++) {
+ value = obj[i];
+ if (value > result) {
+ result = value;
+ }
}
- });
+ } else {
+ iteratee = _.iteratee(iteratee, context);
+ _.each(obj, function(value, index, list) {
+ computed = iteratee(value, index, list);
+ if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
+ result = value;
+ lastComputed = computed;
+ }
+ });
+ }
return result;
};
-
+
- _.min = function(obj, iterator, context) {
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
- return Math.min.apply(Math, obj);
- }
- var result = Infinity, lastComputed = Infinity;
- each(obj, function(value, index, list) {
- var computed = iterator ? iterator.call(context, value, index, list) : value;
- if (computed < lastComputed) {
- result = value;
- lastComputed = computed;
+ _.min = function(obj, iteratee, context) {
+ var result = Infinity, lastComputed = Infinity,
+ value, computed;
+ if (iteratee == null && obj != null) {
+ obj = obj.length === +obj.length ? obj : _.values(obj);
+ for (var i = 0, length = obj.length; i < length; i++) {
+ value = obj[i];
+ if (value < result) {
+ result = value;
+ }
}
- });
+ } else {
+ iteratee = _.iteratee(iteratee, context);
+ _.each(obj, function(value, index, list) {
+ computed = iteratee(value, index, list);
+ if (computed < lastComputed || computed === Infinity && result === Infinity) {
+ result = value;
+ lastComputed = computed;
+ }
+ });
+ }
return result;
};
-
+
- Shuffle an array, using the modern version of the
+
Shuffle a collection, using the modern version of the
Fisher-Yates shuffle.
- _.shuffle = function(obj) {
- var rand;
- var index = 0;
- var shuffled = [];
- each(obj, function(value) {
- rand = _.random(index++);
- shuffled[index - 1] = shuffled[rand];
- shuffled[rand] = value;
- });
+ _.shuffle = function(obj) {
+ var set = obj && obj.length === +obj.length ? obj : _.values(obj);
+ 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.
If n is not specified, returns a single random element.
@@ -699,7 +738,7 @@
Collection Functions
- _.sample = function(obj, n, guard) {
+ _.sample = function(obj, n, guard) {
if (n == null || guard) {
if (obj.length !== +obj.length) obj = _.values(obj);
return obj[_.random(obj.length - 1)];
@@ -710,44 +749,25 @@ Collection Functions
-
-
-
-
- ¶
-
- An internal function to generate lookup iterators.
-
-
-
- var lookupIterator = function(value) {
- if (value == null) return _.identity;
- if (_.isFunction(value)) return value;
- return _.property(value);
- };
-
-
-
-
- Sort the object’s values by a criterion produced by an iterator.
+ Sort the object’s values by a criterion produced by an iteratee.
- _.sortBy = function(obj, iterator, context) {
- iterator = lookupIterator(iterator);
- return _.pluck(_.map(obj, function(value, index, list) {
+ _.sortBy = function(obj, iteratee, context) {
+ iteratee = _.iteratee(iteratee, context);
+ return _.pluck(_.map(obj, function(value, index, list) {
return {
value: value,
index: index,
- criteria: iterator.call(context, value, index, list)
+ criteria: iteratee(value, index, list)
};
- }).sort(function(left, right) {
+ }).sort(function(left, right) {
var a = left.criteria;
var b = right.criteria;
if (a !== b) {
@@ -771,13 +791,13 @@ Collection Functions
- var group = function(behavior) {
- return function(obj, iterator, context) {
+ var group = function(behavior) {
+ return function(obj, iteratee, context) {
var result = {};
- iterator = lookupIterator(iterator);
- each(obj, function(value, index) {
- var key = iterator.call(context, value, index, obj);
- behavior(result, key, value);
+ iteratee = _.iteratee(iteratee, context);
+ _.each(obj, function(value, index) {
+ var key = iteratee(value, index, obj);
+ behavior(result, value, key);
});
return result;
};
@@ -797,8 +817,8 @@ Collection Functions
- _.groupBy = group(function(result, key, value) {
- _.has(result, key) ? result[key].push(value) : result[key] = [value];
+ _.groupBy = group(function(result, value, key) {
+ if (_.has(result, key)) result[key].push(value); else result[key] = [value];
});
@@ -815,7 +835,7 @@ Collection Functions
- _.indexBy = group(function(result, key, value) {
+ _.indexBy = group(function(result, value, key) {
result[key] = value;
});
@@ -834,8 +854,8 @@ Collection Functions
- _.countBy = group(function(result, key) {
- _.has(result, key) ? result[key]++ : result[key] = 1;
+ _.countBy = group(function(result, value, key) {
+ if (_.has(result, key)) result[key]++; else result[key] = 1;
});
@@ -852,13 +872,13 @@ Collection Functions
- _.sortedIndex = function(array, obj, iterator, context) {
- iterator = lookupIterator(iterator);
- var value = iterator.call(context, obj);
+ _.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;
- iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
+ var mid = low + high >>> 1;
+ if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
}
return low;
};
@@ -876,7 +896,7 @@ Collection Functions
- _.toArray = function(obj) {
+ _.toArray = function(obj) {
if (!obj) return [];
if (_.isArray(obj)) return slice.call(obj);
if (obj.length === +obj.length) return _.map(obj, _.identity);
@@ -896,9 +916,9 @@ Collection Functions
- _.size = function(obj) {
+ _.size = function(obj) {
if (obj == null) return 0;
- return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
+ return obj.length === +obj.length ? obj.length : _.keys(obj).length;
};
@@ -910,10 +930,20 @@ Collection Functions
- Array Functions
+ Split a collection into two arrays: one whose elements all satisfy the given
+predicate, and one whose elements all do not satisfy the predicate.
+ _.partition = function(obj, predicate, context) {
+ predicate = _.iteratee(predicate, context);
+ var pass = [], fail = [];
+ _.each(obj, function(value, key, obj) {
+ (predicate(value, key, obj) ? pass : fail).push(value);
+ });
+ return [pass, fail];
+ };
+
@@ -923,7 +953,8 @@ Array Functions
-
+ Array Functions
+
@@ -935,15 +966,27 @@ Array Functions
+
+
+
+
+
+
+
+
+
+
+ ¶
+
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
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 ((n == null) || guard) return array[0];
+ if (n == null || guard) return array[0];
if (n < 0) return [];
return slice.call(array, 0, n);
};
@@ -951,11 +994,11 @@ Array Functions
-
+
Returns everything but the last entry of the array. Especially useful on
the arguments object. Passing n will return all the values in
@@ -964,38 +1007,38 @@
Array Functions
- _.initial = function(array, n, guard) {
- return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
+ _.initial = function(array, n, guard) {
+ 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
values in the array. The guard check allows it to work with _.map
.
- _.last = function(array, n, guard) {
+ _.last = function(array, n, guard) {
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));
};
-
+
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
@@ -1004,114 +1047,95 @@
Array Functions
- _.rest = _.tail = _.drop = function(array, n, guard) {
- return slice.call(array, (n == null) || guard ? 1 : n);
+ _.rest = _.tail = _.drop = function(array, n, guard) {
+ return slice.call(array, n == null || guard ? 1 : n);
};
-
+
- _.compact = function(array) {
+ _.compact = function(array) {
return _.filter(array, _.identity);
};
-
+
- var flatten = function(input, shallow, output) {
+ var flatten = function(input, shallow, strict, output) {
if (shallow && _.every(input, _.isArray)) {
return concat.apply(output, input);
}
- each(input, function(value) {
- if (_.isArray(value) || _.isArguments(value)) {
- shallow ? push.apply(output, value) : flatten(value, shallow, output);
+ for (var i = 0, length = input.length; i < length; i++) {
+ var value = input[i];
+ if (!_.isArray(value) && !_.isArguments(value)) {
+ if (!strict) output.push(value);
+ } else if (shallow) {
+ push.apply(output, value);
} else {
- output.push(value);
+ flatten(value, shallow, strict, output);
}
- });
+ }
return output;
};
-
+
- _.flatten = function(array, shallow) {
- return flatten(array, shallow, []);
+ _.flatten = function(array, shallow) {
+ return flatten(array, shallow, false, []);
};
-
+
- _.without = function(array) {
+ _.without = function(array) {
return _.difference(array, slice.call(arguments, 1));
};
-
-
-
-
- ¶
-
- Split an array into two arrays: one whose elements all satisfy the given
-predicate, and one whose elements all do not satisfy the predicate.
-
-
-
- _.partition = function(array, predicate) {
- var pass = [], fail = [];
- each(array, function(elem) {
- (predicate(elem) ? pass : fail).push(elem);
- });
- return [pass, fail];
- };
-
-
-
-
-
+
@@ -1123,22 +1147,32 @@ Array Functions
- _.uniq = _.unique = function(array, isSorted, iterator, context) {
- if (_.isFunction(isSorted)) {
- context = iterator;
- iterator = isSorted;
+ _.uniq = _.unique = function(array, isSorted, iteratee, context) {
+ if (array == null) return [];
+ if (!_.isBoolean(isSorted)) {
+ context = iteratee;
+ iteratee = isSorted;
isSorted = false;
}
- var initial = iterator ? _.map(array, iterator, context) : array;
- var results = [];
+ if (iteratee != null) iteratee = _.iteratee(iteratee, context);
+ var result = [];
var seen = [];
- each(initial, function(value, index) {
- if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
- seen.push(value);
- results.push(array[index]);
+ for (var i = 0, length = array.length; i < length; i++) {
+ var value = array[i];
+ if (isSorted) {
+ if (!i || seen !== value) result.push(value);
+ seen = value;
+ } else if (iteratee) {
+ var computed = iteratee(value, i, array);
+ if (_.indexOf(seen, computed) < 0) {
+ seen.push(computed);
+ result.push(value);
+ }
+ } else if (_.indexOf(result, value) < 0) {
+ result.push(value);
}
- });
- return results;
+ }
+ return result;
};
@@ -1155,8 +1189,8 @@ Array Functions
- _.union = function() {
- return _.uniq(_.flatten(arguments, true));
+ _.union = function() {
+ return _.uniq(flatten(arguments, true, true, []));
};
@@ -1173,13 +1207,19 @@ Array Functions
- _.intersection = function(array) {
- var rest = slice.call(arguments, 1);
- return _.filter(_.uniq(array), function(item) {
- return _.every(rest, function(other) {
- return _.contains(other, item);
- });
- });
+ _.intersection = function(array) {
+ if (array == null) return [];
+ var result = [];
+ var argsLength = arguments.length;
+ for (var i = 0, length = array.length; i < length; i++) {
+ var item = array[i];
+ if (_.contains(result, item)) continue;
+ for (var j = 1; j < argsLength; j++) {
+ if (!_.contains(arguments[j], item)) break;
+ }
+ if (j === argsLength) result.push(item);
+ }
+ return result;
};
@@ -1196,9 +1236,11 @@ Array Functions
- _.difference = function(array) {
- var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
- return _.filter(array, function(value){ return !_.contains(rest, value); });
+ _.difference = function(array) {
+ var rest = flatten(slice.call(arguments, 1), true, true, []);
+ return _.filter(array, function(value){
+ return !_.contains(rest, value);
+ });
};
@@ -1215,11 +1257,12 @@ Array Functions
- _.zip = function() {
- var length = _.max(_.pluck(arguments, 'length').concat(0));
- var results = new Array(length);
+ _.zip = function(array) {
+ 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);
+ results[i] = _.pluck(arguments, i);
}
return results;
};
@@ -1239,7 +1282,7 @@ Array Functions
- _.object = function(list, values) {
+ _.object = function(list, values) {
if (list == null) return {};
var result = {};
for (var i = 0, length = list.length; i < length; i++) {
@@ -1261,63 +1304,46 @@ Array Functions
- If the browser doesn’t supply us with indexOf (I’m looking at you, MSIE),
-we need this function. Return the position of the first occurrence of an
-item in an array, or -1 if the item is not included in the array.
-Delegates to ECMAScript 5‘s native indexOf
if available.
+
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 = function(array, item, isSorted) {
+ _.indexOf = function(array, item, isSorted) {
if (array == null) return -1;
var i = 0, length = array.length;
if (isSorted) {
if (typeof isSorted == 'number') {
- i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
+ i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
} else {
i = _.sortedIndex(array, item);
return array[i] === item ? i : -1;
}
}
- if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
for (; i < length; i++) if (array[i] === item) return i;
return -1;
- };
-
-
-
-
-
-
-
-
- ¶
-
- Delegates to ECMAScript 5‘s native lastIndexOf
if available.
+ };
-
-
- _.lastIndexOf = function(array, item, from) {
+ _.lastIndexOf = function(array, item, from) {
if (array == null) return -1;
- var hasIndex = from != null;
- if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
- return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
+ var idx = array.length;
+ if (typeof from == 'number') {
+ idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
}
- var i = (hasIndex ? from : array.length);
- while (i--) if (array[i] === item) return i;
+ while (--idx >= 0) if (array[idx] === item) return idx;
return -1;
};
-
+
Generate an integer Array containing an arithmetic progression. A port of
the native Python range()
function. See
@@ -1325,20 +1351,18 @@
Array Functions
- _.range = function(start, stop, step) {
+ _.range = function(start, stop, step) {
if (arguments.length <= 1) {
stop = start || 0;
start = 0;
}
- step = arguments[2] || 1;
+ step = step || 1;
var length = Math.max(Math.ceil((stop - start) / step), 0);
- var idx = 0;
- var range = new Array(length);
+ var range = Array(length);
- while(idx < length) {
- range[idx++] = start;
- start += step;
+ for (var idx = 0; idx < length; idx++, start += step) {
+ range[idx] = start;
}
return range;
@@ -1347,11 +1371,11 @@ Array Functions
-
+
Function (ahem) Functions
@@ -1360,11 +1384,11 @@ Function (ahem) Functions
-
+
@@ -1372,26 +1396,26 @@ Function (ahem) Functions
-
+
- var ctor = function(){};
+ var Ctor = function(){};
-
+
Create a function bound to a given object (assigning this
, and arguments,
optionally). Delegates to ECMAScript 5‘s native Function.bind
if
@@ -1399,30 +1423,31 @@
Function (ahem) Functions
- _.bind = function(func, context) {
+ _.bind = function(func, context) {
var args, bound;
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
- if (!_.isFunction(func)) throw new TypeError;
+ if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
args = slice.call(arguments, 2);
- return bound = function() {
+ bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
- ctor.prototype = func.prototype;
- var self = new ctor;
- ctor.prototype = null;
+ Ctor.prototype = func.prototype;
+ var self = new Ctor;
+ Ctor.prototype = null;
var result = func.apply(self, args.concat(slice.call(arguments)));
- if (Object(result) === result) return result;
+ if (_.isObject(result)) return result;
return self;
};
+ return bound;
};
-
+
Partially apply a function by creating a version that has had some of its
arguments pre-filled, without changing its dynamic this
context. _ acts
@@ -1430,9 +1455,9 @@
Function (ahem) Functions
- _.partial = function(func) {
+ _.partial = function(func) {
var boundArgs = slice.call(arguments, 1);
- return function() {
+ return function() {
var position = 0;
var args = boundArgs.slice();
for (var i = 0, length = args.length; i < length; i++) {
@@ -1446,11 +1471,11 @@ Function (ahem) Functions
-
+
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
@@ -1458,80 +1483,87 @@
Function (ahem) Functions
- _.bindAll = function(obj) {
- var funcs = slice.call(arguments, 1);
- if (funcs.length === 0) throw new Error('bindAll must be passed function names');
- each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
+ _.bindAll = function(obj) {
+ var i, length = arguments.length, key;
+ if (length <= 1) throw new Error('bindAll must be passed function names');
+ for (i = 1; i < length; i++) {
+ key = arguments[i];
+ obj[key] = _.bind(obj[key], obj);
+ }
return obj;
};
-
+
- _.memoize = function(func, hasher) {
- var memo = {};
- hasher || (hasher = _.identity);
- return function() {
- var key = hasher.apply(this, arguments);
- return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
+ _.memoize = function(func, hasher) {
+ var memoize = function(key) {
+ var cache = memoize.cache;
+ var address = hasher ? hasher.apply(this, arguments) : key;
+ if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
+ return cache[address];
};
+ memoize.cache = {};
+ return memoize;
};
-
+
Delays a function for the given number of milliseconds, and then calls
it with the arguments supplied.
- _.delay = function(func, wait) {
+ _.delay = function(func, wait) {
var args = slice.call(arguments, 2);
- return setTimeout(function(){ return func.apply(null, args); }, wait);
+ return setTimeout(function(){
+ return func.apply(null, args);
+ }, wait);
};
-
+
- _.defer = function(func) {
+ _.defer = function(func) {
return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
};
-
+
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
@@ -1541,29 +1573,29 @@
Function (ahem) Functions
- _.throttle = function(func, wait, options) {
+ _.throttle = function(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
- options || (options = {});
- var later = function() {
+ if (!options) options = {};
+ var later = function() {
previous = options.leading === false ? 0 : _.now();
timeout = null;
result = func.apply(context, args);
- context = args = null;
+ if (!timeout) context = args = null;
};
- return function() {
+ return function() {
var now = _.now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
- if (remaining <= 0) {
+ if (remaining <= 0 || remaining > wait) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
- context = args = null;
+ if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
@@ -1574,11 +1606,11 @@ Function (ahem) Functions
-
+
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
@@ -1587,30 +1619,29 @@
Function (ahem) Functions
- _.debounce = function(func, wait, immediate) {
+ _.debounce = function(func, wait, immediate) {
var timeout, args, context, timestamp, result;
- var later = function() {
+ var later = function() {
var last = _.now() - timestamp;
- if (last < wait) {
+
+ if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
if (!immediate) {
result = func.apply(context, args);
- context = args = null;
+ if (!timeout) context = args = null;
}
}
};
- return function() {
+ return function() {
context = this;
args = arguments;
timestamp = _.now();
var callNow = immediate && !timeout;
- if (!timeout) {
- timeout = setTimeout(later, wait);
- }
+ if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
context = args = null;
@@ -1623,25 +1654,38 @@ Function (ahem) Functions
+
+
+
+
+ ¶
+
+ Returns the first function passed as an argument to the second,
+allowing you to adjust arguments, run code before and after, and
+conditionally execute the original function.
+
+
+
+ _.wrap = function(func, wrapper) {
+ return _.partial(wrapper, func);
+ };
+
+
+
+
- Returns a function that will be executed at most one time, no matter how
-often you call it. Useful for lazy initialization.
+ Returns a negated version of the passed-in predicate.
- _.once = function(func) {
- var ran = false, memo;
- return function() {
- if (ran) return memo;
- ran = true;
- memo = func.apply(this, arguments);
- func = null;
- return memo;
+ _.negate = function(predicate) {
+ return function() {
+ return !predicate.apply(this, arguments);
};
};
@@ -1654,14 +1698,20 @@ Function (ahem) Functions
- Returns the first function passed as an argument to the second,
-allowing you to adjust arguments, run code before and after, and
-conditionally execute the original function.
+ Returns a function that is the composition of a list of functions, each
+consuming the return value of the function that follows.
- _.wrap = function(func, wrapper) {
- return _.partial(wrapper, func);
+ _.compose = function() {
+ var args = arguments;
+ var start = args.length - 1;
+ return function() {
+ var i = start;
+ var result = args[start].apply(this, arguments);
+ while (i--) result = args[i].call(this, result);
+ return result;
+ };
};
@@ -1673,19 +1723,15 @@ Function (ahem) Functions
- Returns a function that is the composition of a list of functions, each
-consuming the return value of the function that follows.
+ Returns a function that will only be executed after being called N times.
- _.compose = function() {
- var funcs = arguments;
- return function() {
- var args = arguments;
- for (var i = funcs.length - 1; i >= 0; i--) {
- args = [funcs[i].apply(this, args)];
+ _.after = function(times, func) {
+ return function() {
+ if (--times < 1) {
+ return func.apply(this, arguments);
}
- return args[0];
};
};
@@ -1698,15 +1744,18 @@ Function (ahem) Functions
- Returns a function that will only be executed after being called N times.
+ Returns a function that will only be executed before being called N times.
- _.after = function(times, func) {
- return function() {
- if (--times < 1) {
- return func.apply(this, arguments);
+ _.before = function(times, func) {
+ var memo;
+ return function() {
+ if (--times > 0) {
+ memo = func.apply(this, arguments);
}
+ else func = null;
+ return memo;
};
};
@@ -1719,10 +1768,13 @@ Function (ahem) Functions
- Object Functions
+ Returns a function that will be executed at most one time, no matter how
+often you call it. Useful for lazy initialization.
+ _.once = _.partial(_.before, 2);
+
@@ -1732,7 +1784,8 @@ Object Functions
-
+ Object Functions
+
@@ -1744,12 +1797,24 @@ Object Functions
+
+
+
+
+
+
+
+
+
+
+ ¶
+
Retrieve the names of an object’s properties.
Delegates to ECMAScript 5‘s native Object.keys
- _.keys = function(obj) {
+ _.keys = function(obj) {
if (!_.isObject(obj)) return [];
if (nativeKeys) return nativeKeys(obj);
var keys = [];
@@ -1760,20 +1825,20 @@ Object Functions
-
+
- _.values = function(obj) {
+ _.values = function(obj) {
var keys = _.keys(obj);
var length = keys.length;
- var values = new Array(length);
+ var values = Array(length);
for (var i = 0; i < length; i++) {
values[i] = obj[keys[i]];
}
@@ -1783,20 +1848,20 @@ Object Functions
-
+
- _.pairs = function(obj) {
+ _.pairs = function(obj) {
var keys = _.keys(obj);
var length = keys.length;
- var pairs = new Array(length);
+ var pairs = Array(length);
for (var i = 0; i < length; i++) {
pairs[i] = [keys[i], obj[keys[i]]];
}
@@ -1806,17 +1871,17 @@ Object Functions
-
+
- _.invert = function(obj) {
+ _.invert = function(obj) {
var result = {};
var keys = _.keys(obj);
for (var i = 0, length = keys.length; i < length; i++) {
@@ -1828,18 +1893,18 @@ Object Functions
-
+
- _.functions = _.methods = function(obj) {
+ _.functions = _.methods = function(obj) {
var names = [];
for (var key in obj) {
if (_.isFunction(obj[key])) names.push(key);
@@ -1850,109 +1915,126 @@ Object Functions
-
+
- _.extend = function(obj) {
- each(slice.call(arguments, 1), function(source) {
- if (source) {
- for (var prop in source) {
- obj[prop] = source[prop];
+ _.extend = function(obj) {
+ if (!_.isObject(obj)) return obj;
+ var source, prop;
+ for (var i = 1, length = arguments.length; i < length; i++) {
+ source = arguments[i];
+ for (prop in source) {
+ if (hasOwnProperty.call(source, prop)) {
+ obj[prop] = source[prop];
}
}
- });
+ }
return obj;
};
-
+
- _.pick = function(obj) {
- var copy = {};
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
- each(keys, function(key) {
- if (key in obj) copy[key] = obj[key];
- });
- return copy;
+ _.pick = function(obj, iteratee, context) {
+ var result = {}, key;
+ if (obj == null) return result;
+ if (_.isFunction(iteratee)) {
+ iteratee = createCallback(iteratee, context);
+ for (key in obj) {
+ var value = obj[key];
+ if (iteratee(value, key, obj)) result[key] = value;
+ }
+ } else {
+ var keys = concat.apply([], slice.call(arguments, 1));
+ obj = new Object(obj);
+ for (var i = 0, length = keys.length; i < length; i++) {
+ key = keys[i];
+ if (key in obj) result[key] = obj[key];
+ }
+ }
+ return result;
};
-
+
- _.omit = function(obj) {
- var copy = {};
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
- for (var key in obj) {
- if (!_.contains(keys, key)) copy[key] = obj[key];
+ _.omit = function(obj, iteratee, context) {
+ if (_.isFunction(iteratee)) {
+ iteratee = _.negate(iteratee);
+ } else {
+ var keys = _.map(concat.apply([], slice.call(arguments, 1)), String);
+ iteratee = function(value, key) {
+ return !_.contains(keys, key);
+ };
}
- return copy;
+ return _.pick(obj, iteratee, context);
};
-
+
- _.defaults = function(obj) {
- each(slice.call(arguments, 1), function(source) {
- if (source) {
- for (var prop in source) {
- if (obj[prop] === void 0) obj[prop] = source[prop];
- }
+ _.defaults = function(obj) {
+ if (!_.isObject(obj)) return obj;
+ for (var i = 1, length = arguments.length; i < length; i++) {
+ var source = arguments[i];
+ for (var prop in source) {
+ if (obj[prop] === void 0) obj[prop] = source[prop];
}
- });
+ }
return obj;
};
-
+
- _.clone = function(obj) {
+ _.clone = function(obj) {
if (!_.isObject(obj)) return obj;
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
@@ -1960,11 +2042,11 @@ Object Functions
-
+
Invokes interceptor with the obj, and then returns obj.
The primary purpose of this method is to “tap into” a method chain, in
@@ -1972,7 +2054,7 @@
Object Functions
- _.tap = function(obj, interceptor) {
+ _.tap = function(obj, interceptor) {
interceptor(obj);
return obj;
};
@@ -1980,42 +2062,42 @@ Object Functions
-
+
- var eq = function(a, b, aStack, bStack) {
+ var eq = function(a, b, aStack, bStack) {
-
+
Identical objects are equal. 0 === -0
, but they aren’t identical.
See the Harmony egal
proposal.
- 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
.
@@ -2026,11 +2108,11 @@ Object Functions
-
+
Unwrap any wrapped objects.
@@ -2042,51 +2124,34 @@ Object Functions
-
+
var className = toString.call(a);
- if (className != toString.call(b)) return false;
+ if (className !== toString.call(b)) return false;
switch (className) {
-
-
-
-
- ¶
-
- Strings, numbers, dates, and booleans are compared by value.
-
-
-
- case '[object String]':
-
-
-
-
- Primitives and their corresponding object wrappers are equivalent; thus, "5"
is
-equivalent to new String("5")
.
+ Strings, numbers, regular expressions, dates, and booleans are compared by value.
- return a == String(b);
- case '[object Number]':
+ case '[object RegExp]':
@@ -2097,14 +2162,11 @@ Object Functions
- NaN
s are equivalent, but non-reflexive. An egal
comparison is performed for
-other numeric values.
+ RegExps are coerced to strings for comparison (Note: ‘’ + /a/i === ‘/a/i’)
- return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
- case '[object Date]':
- case '[object Boolean]':
+ case '[object String]':
@@ -2115,13 +2177,13 @@ Object Functions
- Coerce dates and booleans to numeric primitive values. Dates are compared by their
-millisecond representations. Note that invalid dates with millisecond representations
-of NaN
are not equivalent.
+ Primitives and their corresponding object wrappers are equivalent; thus, "5"
is
+equivalent to new String("5")
.
- return +a == +b;
+ return '' + a === '' + b;
+ case '[object Number]':
@@ -2132,17 +2194,12 @@ Object Functions
- RegExps are compared by their source patterns and flags.
+ NaN
s are equivalent, but non-reflexive.
+Object(NaN) is equivalent to NaN
- case '[object RegExp]':
- return a.source == b.source &&
- a.global == b.global &&
- a.multiline == b.multiline &&
- a.ignoreCase == b.ignoreCase;
- }
- if (typeof a != 'object' || typeof b != 'object') return false;
+ if (+a !== +a) return +b !== +b;
@@ -2153,13 +2210,13 @@ Object Functions
- Assume equality for cyclic structures. The algorithm for detecting cyclic
-structures is adapted from ES 5.1 section 15.12.3, abstract operation JO
.
+ An egal
comparison is performed for other numeric values.
- var length = aStack.length;
- while (length--) {
+ return +a === 0 ? 1 / +a === 1 / b : +a === +b;
+ case '[object Date]':
+ case '[object Boolean]':
@@ -2170,13 +2227,15 @@ Object Functions
- Linear search. Performance is inversely proportional to the number of
-unique nested structures.
+ Coerce dates and booleans to numeric primitive values. Dates are compared by their
+millisecond representations. Note that invalid dates with millisecond representations
+of NaN
are not equivalent.
- if (aStack[length] == a) return bStack[length] == b;
- }
+ return +a === +b;
+ }
+ if (typeof a != 'object' || typeof b != 'object') return false;
@@ -2187,17 +2246,13 @@ Object Functions
- Objects with different constructors are not equivalent, but Object
s
-from different frames are.
+ Assume equality for cyclic structures. The algorithm for detecting cyclic
+structures is adapted from ES 5.1 section 15.12.3, abstract operation JO
.
- 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;
- }
+ var length = aStack.length;
+ while (length--) {
@@ -2208,13 +2263,13 @@ Object Functions
- Add the first object to the stack of traversed objects.
+ Linear search. Performance is inversely proportional to the number of
+unique nested structures.
- aStack.push(a);
- bStack.push(b);
- var size = 0, result = true;
+ if (aStack[length] === a) return bStack[length] === b;
+ }
@@ -2225,11 +2280,14 @@ Object Functions
- Recursively compare objects and arrays.
+ Objects with different constructors are not equivalent, but Object
s
+from different frames are.
- if (className == '[object Array]') {
+ var aCtor = a.constructor, bCtor = b.constructor;
+ if (
+ aCtor !== bCtor &&
@@ -2240,13 +2298,16 @@ Object Functions
- Compare array lengths to determine if a deep comparison is necessary.
+ Handle Object.create(x) cases
- size = a.length;
- result = size == b.length;
- if (result) {
+ 'constructor' in a && 'constructor' in b &&
+ !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
+ _.isFunction(bCtor) && bCtor instanceof bCtor)
+ ) {
+ return false;
+ }
@@ -2257,15 +2318,13 @@ Object Functions
- Deep compare the contents, ignoring non-numeric properties.
+ Add the first object to the stack of traversed objects.
- while (size--) {
- if (!(result = eq(a[size], b[size], aStack, bStack))) break;
- }
- }
- } else {
+ aStack.push(a);
+ bStack.push(b);
+ var size, result;
@@ -2276,12 +2335,11 @@ Object Functions
- Deep compare objects.
+ Recursively compare objects and arrays.
- for (var key in a) {
- if (_.has(a, key)) {
+ if (className === '[object Array]') {
@@ -2292,11 +2350,13 @@ Object Functions
- Count the expected number of properties.
+ Compare array lengths to determine if a deep comparison is necessary.
- size++;
+ size = a.length;
+ result = size === b.length;
+ if (result) {
@@ -2307,13 +2367,15 @@ Object Functions
- Deep compare each member.
+ Deep compare the contents, ignoring non-numeric properties.
- if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
+ while (size--) {
+ if (!(result = eq(a[size], b[size], aStack, bStack))) break;
}
- }
+ }
+ } else {
@@ -2324,26 +2386,57 @@ Object Functions
- Ensure that both objects contain the same number of properties.
+ Deep compare objects.
- if (result) {
- for (key in b) {
- if (_.has(b, key) && !(size--)) break;
+ var keys = _.keys(a), key;
+ size = keys.length;
+
+
+
+
+
+
+
+
+ ¶
+
+ Ensure that both objects contain the same number of properties before comparing deep equality.
+
+
+
+ result = _.keys(b).length === size;
+ if (result) {
+ while (size--) {
+
+
+
+
+
+
+
+
+ ¶
+
+ Deep compare each member
+
+
+
+ key = keys[size];
+ if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
}
- result = !size;
}
}
-
+
Remove the first object from the stack of traversed objects.
@@ -2357,37 +2450,37 @@ Object Functions
-
+
- _.isEqual = function(a, b) {
+ _.isEqual = function(a, b) {
return eq(a, b, [], []);
};
-
+
Is a given array, string, or object empty?
An “empty” object has no enumerable own-properties.
- _.isEmpty = function(obj) {
+ _.isEmpty = function(obj) {
if (obj == null) return true;
- if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
+ if (_.isArray(obj) || _.isString(obj) || _.isArguments(obj)) return obj.length === 0;
for (var key in obj) if (_.has(obj, key)) return false;
return true;
};
@@ -2395,82 +2488,83 @@ Object Functions
-
+
- _.isElement = function(obj) {
+ _.isElement = function(obj) {
return !!(obj && obj.nodeType === 1);
};
-
+
- _.isArray = nativeIsArray || function(obj) {
- return toString.call(obj) == '[object Array]';
+ _.isArray = nativeIsArray || function(obj) {
+ return toString.call(obj) === '[object Array]';
};
-
+
- _.isObject = function(obj) {
- return obj === Object(obj);
+ _.isObject = function(obj) {
+ var type = typeof obj;
+ return type === 'function' || type === 'object' && !!obj;
};
-
+
- each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
- _['is' + name] = function(obj) {
- return toString.call(obj) == '[object ' + name + ']';
+ _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
+ _['is' + name] = function(obj) {
+ return toString.call(obj) === '[object ' + name + ']';
};
});
-
+
Define a fallback version of the method in browsers (ahem, IE), where
there isn’t any inspectable “Arguments” type.
@@ -2478,141 +2572,141 @@ Object Functions
if (!_.isArguments(arguments)) {
- _.isArguments = function(obj) {
- return !!(obj && _.has(obj, 'callee'));
+ _.isArguments = function(obj) {
+ return _.has(obj, 'callee');
};
}
-
+
- Optimize isFunction
if appropriate.
+ Optimize isFunction
if appropriate. Work around an IE 11 bug.
- if (typeof (/./) !== 'function') {
- _.isFunction = function(obj) {
- return typeof obj === 'function';
+ if (typeof /./ !== 'function') {
+ _.isFunction = function(obj) {
+ return typeof obj == 'function' || false;
};
}
-
+
- _.isFinite = function(obj) {
+ _.isFinite = function(obj) {
return isFinite(obj) && !isNaN(parseFloat(obj));
};
-
+
- _.isNaN = function(obj) {
- return _.isNumber(obj) && obj != +obj;
+ _.isNaN = function(obj) {
+ return _.isNumber(obj) && obj !== +obj;
};
-
+
- _.isBoolean = function(obj) {
- return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
+ _.isBoolean = function(obj) {
+ return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
};
-
+
- _.isNull = function(obj) {
+ _.isNull = function(obj) {
return obj === null;
};
-
+
- _.isUndefined = function(obj) {
+ _.isUndefined = function(obj) {
return obj === void 0;
};
-
+
Shortcut function for checking if an object has a given property directly
on itself (in other words, not on a prototype).
- _.has = function(obj, key) {
- return hasOwnProperty.call(obj, key);
+ _.has = function(obj, key) {
+ return obj != null && hasOwnProperty.call(obj, key);
};
-
+