mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-14 12:47:49 +00:00
Update Underscore/Backbone tests and make them passable.
This commit is contained in:
412
vendor/underscore/underscore.js
vendored
412
vendor/underscore/underscore.js
vendored
@@ -8,29 +8,32 @@
|
||||
// Baseline setup
|
||||
// --------------
|
||||
|
||||
// Establish the root object, `window` in the browser, or `exports` on the server.
|
||||
var root = this;
|
||||
// Establish the root object, `window` (`self`) in the browser, `global`
|
||||
// on the server, or `this` in some virtual machines. We use `self`
|
||||
// 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.
|
||||
var previousUnderscore = root._;
|
||||
|
||||
// Save bytes in the minified (but not gzipped) version:
|
||||
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
|
||||
var ArrayProto = Array.prototype, ObjProto = Object.prototype;
|
||||
|
||||
// Create quick reference variables for speed access to core prototypes.
|
||||
var
|
||||
push = ArrayProto.push,
|
||||
slice = ArrayProto.slice,
|
||||
toString = ObjProto.toString,
|
||||
hasOwnProperty = ObjProto.hasOwnProperty;
|
||||
push = ArrayProto.push,
|
||||
slice = ArrayProto.slice,
|
||||
toString = ObjProto.toString,
|
||||
hasOwnProperty = ObjProto.hasOwnProperty;
|
||||
|
||||
// All **ECMAScript 5** native function implementations that we hope to use
|
||||
// are declared here.
|
||||
var
|
||||
nativeIsArray = Array.isArray,
|
||||
nativeKeys = Object.keys,
|
||||
nativeBind = FuncProto.bind,
|
||||
nativeCreate = Object.create;
|
||||
nativeIsArray = Array.isArray,
|
||||
nativeKeys = Object.keys,
|
||||
nativeCreate = Object.create;
|
||||
|
||||
// Naked function reference for surrogate-prototype-swapping.
|
||||
var Ctor = function(){};
|
||||
@@ -43,7 +46,7 @@
|
||||
};
|
||||
|
||||
// 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.
|
||||
if (typeof exports !== 'undefined') {
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
@@ -66,9 +69,8 @@
|
||||
case 1: return function(value) {
|
||||
return func.call(context, value);
|
||||
};
|
||||
case 2: return function(value, other) {
|
||||
return func.call(context, value, other);
|
||||
};
|
||||
// The 2-parameter case has been omitted only because no current consumers
|
||||
// made use of it.
|
||||
case 3: return function(value, index, collection) {
|
||||
return func.call(context, value, index, collection);
|
||||
};
|
||||
@@ -94,21 +96,27 @@
|
||||
return cb(value, context, Infinity);
|
||||
};
|
||||
|
||||
// An internal function for creating assigner functions.
|
||||
var createAssigner = function(keysFunc, undefinedOnly) {
|
||||
return function(obj) {
|
||||
var length = arguments.length;
|
||||
if (length < 2 || obj == null) return obj;
|
||||
for (var index = 1; index < length; index++) {
|
||||
var source = arguments[index],
|
||||
keys = keysFunc(source),
|
||||
l = keys.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
var key = keys[i];
|
||||
if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
|
||||
}
|
||||
// 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];
|
||||
}
|
||||
return obj;
|
||||
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);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -175,30 +183,29 @@
|
||||
};
|
||||
|
||||
// Create a reducing function iterating left or right.
|
||||
function createReduce(dir) {
|
||||
var createReduce = function(dir) {
|
||||
// Optimized iterator function as using arguments.length
|
||||
// in the main function will deoptimize the, see #1991.
|
||||
function iterator(obj, iteratee, memo, keys, index, length) {
|
||||
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) {
|
||||
iteratee = optimizeCb(iteratee, context, 4);
|
||||
var keys = !isArrayLike(obj) && _.keys(obj),
|
||||
length = (keys || obj).length,
|
||||
index = dir > 0 ? 0 : length - 1;
|
||||
// Determine the initial value if none is provided.
|
||||
if (arguments.length < 3) {
|
||||
memo = obj[keys ? keys[index] : index];
|
||||
index += dir;
|
||||
}
|
||||
return iterator(obj, iteratee, memo, keys, index, length);
|
||||
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`,
|
||||
// or `foldl`.
|
||||
@@ -269,14 +276,13 @@
|
||||
};
|
||||
|
||||
// Invoke a method (with arguments) on every item in a collection.
|
||||
_.invoke = function(obj, method) {
|
||||
var args = slice.call(arguments, 2);
|
||||
_.invoke = restArgs(function(obj, method, args) {
|
||||
var isFunc = _.isFunction(method);
|
||||
return _.map(obj, function(value) {
|
||||
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.
|
||||
_.pluck = function(obj, key) {
|
||||
@@ -299,7 +305,7 @@
|
||||
_.max = function(obj, iteratee, context) {
|
||||
var result = -Infinity, lastComputed = -Infinity,
|
||||
value, computed;
|
||||
if (iteratee == null && obj != null) {
|
||||
if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object') && obj != null) {
|
||||
obj = isArrayLike(obj) ? obj : _.values(obj);
|
||||
for (var i = 0, length = obj.length; i < length; i++) {
|
||||
value = obj[i];
|
||||
@@ -309,10 +315,10 @@
|
||||
}
|
||||
} else {
|
||||
iteratee = cb(iteratee, context);
|
||||
_.each(obj, function(value, index, list) {
|
||||
computed = iteratee(value, index, list);
|
||||
_.each(obj, function(v, index, list) {
|
||||
computed = iteratee(v, index, list);
|
||||
if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
|
||||
result = value;
|
||||
result = v;
|
||||
lastComputed = computed;
|
||||
}
|
||||
});
|
||||
@@ -324,7 +330,7 @@
|
||||
_.min = function(obj, iteratee, context) {
|
||||
var result = Infinity, lastComputed = Infinity,
|
||||
value, computed;
|
||||
if (iteratee == null && obj != null) {
|
||||
if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object') && obj != null) {
|
||||
obj = isArrayLike(obj) ? obj : _.values(obj);
|
||||
for (var i = 0, length = obj.length; i < length; i++) {
|
||||
value = obj[i];
|
||||
@@ -334,10 +340,10 @@
|
||||
}
|
||||
} else {
|
||||
iteratee = cb(iteratee, context);
|
||||
_.each(obj, function(value, index, list) {
|
||||
computed = iteratee(value, index, list);
|
||||
_.each(obj, function(v, index, list) {
|
||||
computed = iteratee(v, index, list);
|
||||
if (computed < lastComputed || computed === Infinity && result === Infinity) {
|
||||
result = value;
|
||||
result = v;
|
||||
lastComputed = computed;
|
||||
}
|
||||
});
|
||||
@@ -345,21 +351,13 @@
|
||||
return result;
|
||||
};
|
||||
|
||||
// Shuffle a collection, using the modern version of the
|
||||
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
|
||||
// Shuffle a collection.
|
||||
_.shuffle = function(obj) {
|
||||
var set = isArrayLike(obj) ? 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;
|
||||
return _.sample(obj, Infinity);
|
||||
};
|
||||
|
||||
// Sample **n** random values from a collection.
|
||||
// Sample **n** random values from a collection using the modern version of the
|
||||
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
|
||||
// If **n** is not specified, returns a single random element.
|
||||
// The internal `guard` argument allows it to work with `map`.
|
||||
_.sample = function(obj, n, guard) {
|
||||
@@ -367,17 +365,28 @@
|
||||
if (!isArrayLike(obj)) obj = _.values(obj);
|
||||
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.
|
||||
_.sortBy = function(obj, iteratee, context) {
|
||||
var index = 0;
|
||||
iteratee = cb(iteratee, context);
|
||||
return _.pluck(_.map(obj, function(value, index, list) {
|
||||
return _.pluck(_.map(obj, function(value, key, list) {
|
||||
return {
|
||||
value: value,
|
||||
index: index,
|
||||
criteria: iteratee(value, index, list)
|
||||
index: index++,
|
||||
criteria: iteratee(value, key, list)
|
||||
};
|
||||
}).sort(function(left, right) {
|
||||
var a = left.criteria;
|
||||
@@ -391,9 +400,9 @@
|
||||
};
|
||||
|
||||
// An internal function used for aggregate "group by" operations.
|
||||
var group = function(behavior) {
|
||||
var group = function(behavior, partition) {
|
||||
return function(obj, iteratee, context) {
|
||||
var result = {};
|
||||
var result = partition ? [[], []] : {};
|
||||
iteratee = cb(iteratee, context);
|
||||
_.each(obj, function(value, index) {
|
||||
var key = iteratee(value, index, obj);
|
||||
@@ -438,14 +447,9 @@
|
||||
|
||||
// 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 = cb(predicate, context);
|
||||
var pass = [], fail = [];
|
||||
_.each(obj, function(value, key, obj) {
|
||||
(predicate(value, key, obj) ? pass : fail).push(value);
|
||||
});
|
||||
return [pass, fail];
|
||||
};
|
||||
_.partition = group(function(result, value, pass) {
|
||||
result[pass ? 0 : 1].push(value);
|
||||
}, true);
|
||||
|
||||
// Array Functions
|
||||
// ---------------
|
||||
@@ -487,17 +491,19 @@
|
||||
};
|
||||
|
||||
// Internal implementation of a recursive `flatten` function.
|
||||
var flatten = function(input, shallow, strict, startIndex) {
|
||||
var output = [], idx = 0;
|
||||
for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
|
||||
var flatten = function(input, shallow, strict, output) {
|
||||
output = output || [];
|
||||
var idx = output.length;
|
||||
for (var i = 0, length = getLength(input); i < length; i++) {
|
||||
var value = input[i];
|
||||
if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
|
||||
//flatten current level of array or arguments object
|
||||
if (!shallow) value = flatten(value, shallow, strict);
|
||||
var j = 0, len = value.length;
|
||||
output.length += len;
|
||||
while (j < len) {
|
||||
output[idx++] = value[j++];
|
||||
if (shallow) {
|
||||
var j = 0, len = value.length;
|
||||
while (j < len) output[idx++] = value[j++];
|
||||
} else {
|
||||
flatten(value, shallow, strict, output);
|
||||
idx = output.length;
|
||||
}
|
||||
} else if (!strict) {
|
||||
output[idx++] = value;
|
||||
@@ -512,9 +518,9 @@
|
||||
};
|
||||
|
||||
// Return a version of the array that does not contain the specified value(s).
|
||||
_.without = function(array) {
|
||||
return _.difference(array, slice.call(arguments, 1));
|
||||
};
|
||||
_.without = restArgs(function(array, otherArrays) {
|
||||
return _.difference(array, otherArrays);
|
||||
});
|
||||
|
||||
// Produce a duplicate-free version of the array. If the array has already
|
||||
// been sorted, you have the option of using a faster algorithm.
|
||||
@@ -548,9 +554,9 @@
|
||||
|
||||
// Produce an array that contains the union: each distinct element from all of
|
||||
// the passed-in arrays.
|
||||
_.union = function() {
|
||||
return _.uniq(flatten(arguments, true, true));
|
||||
};
|
||||
_.union = restArgs(function(arrays) {
|
||||
return _.uniq(flatten(arrays, true, true));
|
||||
});
|
||||
|
||||
// Produce an array that contains every item shared between all the
|
||||
// passed-in arrays.
|
||||
@@ -560,7 +566,8 @@
|
||||
for (var i = 0, length = getLength(array); i < length; i++) {
|
||||
var item = array[i];
|
||||
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 (j === argsLength) result.push(item);
|
||||
@@ -570,18 +577,12 @@
|
||||
|
||||
// Take the difference between one array and a number of other arrays.
|
||||
// Only the elements present in just the first array will remain.
|
||||
_.difference = function(array) {
|
||||
var rest = flatten(arguments, true, true, 1);
|
||||
_.difference = restArgs(function(array, rest) {
|
||||
rest = flatten(rest, true, true);
|
||||
return _.filter(array, function(value){
|
||||
return !_.contains(rest, value);
|
||||
});
|
||||
};
|
||||
|
||||
// Zip together multiple lists into a single array -- elements that share
|
||||
// an index go together.
|
||||
_.zip = function() {
|
||||
return _.unzip(arguments);
|
||||
};
|
||||
});
|
||||
|
||||
// Complement of _.zip. Unzip accepts an array of arrays and groups
|
||||
// each array's elements on shared indices
|
||||
@@ -595,6 +596,10 @@
|
||||
return result;
|
||||
};
|
||||
|
||||
// Zip together multiple lists into a single array -- elements that share
|
||||
// an index go together.
|
||||
_.zip = restArgs(_.unzip);
|
||||
|
||||
// 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
|
||||
// the corresponding values.
|
||||
@@ -611,7 +616,7 @@
|
||||
};
|
||||
|
||||
// Generator function to create the findIndex and findLastIndex functions
|
||||
function createPredicateIndexFinder(dir) {
|
||||
var createPredicateIndexFinder = function(dir) {
|
||||
return function(array, predicate, context) {
|
||||
predicate = cb(predicate, context);
|
||||
var length = getLength(array);
|
||||
@@ -621,7 +626,7 @@
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Returns the first index on an array-like that passes a predicate test
|
||||
_.findIndex = createPredicateIndexFinder(1);
|
||||
@@ -641,14 +646,14 @@
|
||||
};
|
||||
|
||||
// Generator function to create the indexOf and lastIndexOf functions
|
||||
function createIndexFinder(dir, predicateFind, sortedIndex) {
|
||||
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);
|
||||
i = idx >= 0 ? idx : Math.max(idx + length, i);
|
||||
} else {
|
||||
length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
|
||||
length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
|
||||
}
|
||||
} else if (sortedIndex && idx && length) {
|
||||
idx = sortedIndex(array, item);
|
||||
@@ -663,7 +668,7 @@
|
||||
}
|
||||
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.
|
||||
@@ -692,6 +697,19 @@
|
||||
return range;
|
||||
};
|
||||
|
||||
// Split an **array** into several arrays containing **count** or less elements
|
||||
// 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
|
||||
// ------------------
|
||||
|
||||
@@ -708,45 +726,46 @@
|
||||
// Create a function bound to a given object (assigning `this`, and arguments,
|
||||
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
|
||||
// available.
|
||||
_.bind = function(func, context) {
|
||||
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
|
||||
_.bind = restArgs(function(func, context, args) {
|
||||
if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
|
||||
var args = slice.call(arguments, 2);
|
||||
var bound = function() {
|
||||
return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
|
||||
};
|
||||
var bound = restArgs(function(callArgs) {
|
||||
return executeBound(func, bound, context, this, args.concat(callArgs));
|
||||
});
|
||||
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
|
||||
// as a placeholder, allowing any combination of arguments to be pre-filled.
|
||||
_.partial = function(func) {
|
||||
var boundArgs = slice.call(arguments, 1);
|
||||
// as a placeholder by default, allowing any combination of arguments to be
|
||||
// pre-filled. Set `_.partial.placeholder` for a custom placeholder argument.
|
||||
_.partial = restArgs(function(func, boundArgs) {
|
||||
var placeholder = _.partial.placeholder;
|
||||
var bound = function() {
|
||||
var position = 0, length = boundArgs.length;
|
||||
var args = Array(length);
|
||||
for (var i = 0; i < length; i++) {
|
||||
args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
|
||||
args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i];
|
||||
}
|
||||
while (position < arguments.length) args.push(arguments[position++]);
|
||||
return executeBound(func, bound, this, this, args);
|
||||
};
|
||||
return bound;
|
||||
};
|
||||
});
|
||||
|
||||
_.partial.placeholder = _;
|
||||
|
||||
// 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
|
||||
// defined on an object belong to it.
|
||||
_.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];
|
||||
_.bindAll = restArgs(function(obj, keys) {
|
||||
keys = flatten(keys, false, false);
|
||||
var index = keys.length;
|
||||
if (index < 1) throw new Error('bindAll must be passed function names');
|
||||
while (index--) {
|
||||
var key = keys[index];
|
||||
obj[key] = _.bind(obj[key], obj);
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
});
|
||||
|
||||
// Memoize an expensive function by storing its results.
|
||||
_.memoize = function(func, hasher) {
|
||||
@@ -762,12 +781,11 @@
|
||||
|
||||
// Delays a function for the given number of milliseconds, and then calls
|
||||
// it with the arguments supplied.
|
||||
_.delay = function(func, wait) {
|
||||
var args = slice.call(arguments, 2);
|
||||
_.delay = restArgs(function(func, wait, args) {
|
||||
return setTimeout(function(){
|
||||
return func.apply(null, args);
|
||||
}, wait);
|
||||
};
|
||||
});
|
||||
|
||||
// Defers a function, scheduling it to run after the current call stack has
|
||||
// cleared.
|
||||
@@ -898,6 +916,8 @@
|
||||
// often you call it. Useful for lazy initialization.
|
||||
_.once = _.partial(_.before, 2);
|
||||
|
||||
_.restArgs = restArgs;
|
||||
|
||||
// Object Functions
|
||||
// ----------------
|
||||
|
||||
@@ -906,10 +926,10 @@
|
||||
var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
|
||||
'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
|
||||
|
||||
function collectNonEnumProps(obj, keys) {
|
||||
var collectNonEnumProps = function(obj, keys) {
|
||||
var nonEnumIdx = nonEnumerableProps.length;
|
||||
var constructor = obj.constructor;
|
||||
var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;
|
||||
var proto = _.isFunction(constructor) && constructor.prototype || ObjProto;
|
||||
|
||||
// Constructor is a special case.
|
||||
var prop = 'constructor';
|
||||
@@ -921,7 +941,7 @@
|
||||
keys.push(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Retrieve the names of an object's own properties.
|
||||
// Delegates to **ECMAScript 5**'s native `Object.keys`
|
||||
@@ -960,15 +980,14 @@
|
||||
// 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 = {},
|
||||
currentKey;
|
||||
for (var index = 0; index < length; index++) {
|
||||
currentKey = keys[index];
|
||||
results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
|
||||
}
|
||||
return results;
|
||||
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.
|
||||
@@ -1002,6 +1021,25 @@
|
||||
return names.sort();
|
||||
};
|
||||
|
||||
// An internal function for creating assigner functions.
|
||||
var createAssigner = function(keysFunc, defaults) {
|
||||
return function(obj) {
|
||||
var length = arguments.length;
|
||||
if (defaults) obj = Object(obj);
|
||||
if (length < 2 || obj == null) return obj;
|
||||
for (var index = 1; index < length; index++) {
|
||||
var source = arguments[index],
|
||||
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);
|
||||
|
||||
@@ -1019,16 +1057,21 @@
|
||||
}
|
||||
};
|
||||
|
||||
// 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.
|
||||
_.pick = function(object, oiteratee, context) {
|
||||
var result = {}, obj = object, iteratee, keys;
|
||||
_.pick = restArgs(function(obj, keys) {
|
||||
var result = {}, iteratee = keys[0];
|
||||
if (obj == null) return result;
|
||||
if (_.isFunction(oiteratee)) {
|
||||
if (_.isFunction(iteratee)) {
|
||||
if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]);
|
||||
keys = _.allKeys(obj);
|
||||
iteratee = optimizeCb(oiteratee, context);
|
||||
} else {
|
||||
keys = flatten(arguments, false, false, 1);
|
||||
iteratee = function(value, key, obj) { return key in obj; };
|
||||
iteratee = keyInObj;
|
||||
keys = flatten(keys, false, false);
|
||||
obj = Object(obj);
|
||||
}
|
||||
for (var i = 0, length = keys.length; i < length; i++) {
|
||||
@@ -1037,20 +1080,22 @@
|
||||
if (iteratee(value, key, obj)) result[key] = value;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
});
|
||||
|
||||
// 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)) {
|
||||
iteratee = _.negate(iteratee);
|
||||
if (keys.length > 1) context = keys[1];
|
||||
} else {
|
||||
var keys = _.map(flatten(arguments, false, false, 1), String);
|
||||
keys = _.map(flatten(keys, false, false), String);
|
||||
iteratee = function(value, key) {
|
||||
return !_.contains(keys, key);
|
||||
};
|
||||
}
|
||||
return _.pick(obj, iteratee, context);
|
||||
};
|
||||
});
|
||||
|
||||
// Fill in a given object with default properties.
|
||||
_.defaults = createAssigner(_.allKeys, true);
|
||||
@@ -1092,12 +1137,23 @@
|
||||
|
||||
|
||||
// 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.
|
||||
// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
|
||||
if (a === b) return a !== 0 || 1 / a === 1 / b;
|
||||
// A strict comparison is necessary because `null == undefined`.
|
||||
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.
|
||||
if (a instanceof _) a = a._wrapped;
|
||||
if (b instanceof _) b = b._wrapped;
|
||||
@@ -1230,8 +1286,9 @@
|
||||
}
|
||||
|
||||
// Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
|
||||
// IE 11 (#1621), and in Safari 8 (#1929).
|
||||
if (typeof /./ != 'function' && typeof Int8Array != 'object') {
|
||||
// IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236).
|
||||
var nodelist = root.document && root.document.childNodes;
|
||||
if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') {
|
||||
_.isFunction = function(obj) {
|
||||
return typeof obj == 'function' || false;
|
||||
};
|
||||
@@ -1242,9 +1299,9 @@
|
||||
return isFinite(obj) && !isNaN(parseFloat(obj));
|
||||
};
|
||||
|
||||
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
|
||||
// Is the given value `NaN`?
|
||||
_.isNaN = function(obj) {
|
||||
return _.isNumber(obj) && obj !== +obj;
|
||||
return _.isNumber(obj) && isNaN(obj);
|
||||
};
|
||||
|
||||
// Is a given value a boolean?
|
||||
@@ -1362,8 +1419,8 @@
|
||||
|
||||
// If the value of the named `property` is a function then invoke it with the
|
||||
// `object` as context; otherwise, return it.
|
||||
_.result = function(object, property, fallback) {
|
||||
var value = object == null ? void 0 : object[property];
|
||||
_.result = function(object, prop, fallback) {
|
||||
var value = object == null ? void 0 : object[prop];
|
||||
if (value === void 0) {
|
||||
value = fallback;
|
||||
}
|
||||
@@ -1381,9 +1438,9 @@
|
||||
// By default, Underscore uses ERB-style template delimiters, change the
|
||||
// following template settings to use alternative delimiters.
|
||||
_.templateSettings = {
|
||||
evaluate : /<%([\s\S]+?)%>/g,
|
||||
interpolate : /<%=([\s\S]+?)%>/g,
|
||||
escape : /<%-([\s\S]+?)%>/g
|
||||
evaluate: /<%([\s\S]+?)%>/g,
|
||||
interpolate: /<%=([\s\S]+?)%>/g,
|
||||
escape: /<%-([\s\S]+?)%>/g
|
||||
};
|
||||
|
||||
// When customizing `templateSettings`, if you don't want to define an
|
||||
@@ -1394,15 +1451,15 @@
|
||||
// Certain characters need to be escaped so that they can be put into a
|
||||
// string literal.
|
||||
var escapes = {
|
||||
"'": "'",
|
||||
'\\': '\\',
|
||||
'\r': 'r',
|
||||
'\n': 'n',
|
||||
"'": "'",
|
||||
'\\': '\\',
|
||||
'\r': 'r',
|
||||
'\n': 'n',
|
||||
'\u2028': 'u2028',
|
||||
'\u2029': 'u2029'
|
||||
};
|
||||
|
||||
var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
|
||||
var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g;
|
||||
|
||||
var escapeChar = function(match) {
|
||||
return '\\' + escapes[match];
|
||||
@@ -1427,7 +1484,7 @@
|
||||
var index = 0;
|
||||
var source = "__p+='";
|
||||
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;
|
||||
|
||||
if (escape) {
|
||||
@@ -1438,7 +1495,7 @@
|
||||
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;
|
||||
});
|
||||
source += "';\n";
|
||||
@@ -1450,8 +1507,9 @@
|
||||
"print=function(){__p+=__j.call(arguments,'');};\n" +
|
||||
source + 'return __p;\n';
|
||||
|
||||
var render;
|
||||
try {
|
||||
var render = new Function(settings.variable || 'obj', '_', source);
|
||||
render = new Function(settings.variable || 'obj', '_', source);
|
||||
} catch (e) {
|
||||
e.source = source;
|
||||
throw e;
|
||||
@@ -1482,7 +1540,7 @@
|
||||
// underscore functions. Wrapped objects may be chained.
|
||||
|
||||
// Helper function to continue chaining intermediate results.
|
||||
var result = function(instance, obj) {
|
||||
var chainResult = function(instance, obj) {
|
||||
return instance._chain ? _(obj).chain() : obj;
|
||||
};
|
||||
|
||||
@@ -1493,7 +1551,7 @@
|
||||
_.prototype[name] = function() {
|
||||
var args = [this._wrapped];
|
||||
push.apply(args, arguments);
|
||||
return result(this, func.apply(_, args));
|
||||
return chainResult(this, func.apply(_, args));
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -1508,7 +1566,7 @@
|
||||
var obj = this._wrapped;
|
||||
method.apply(obj, arguments);
|
||||
if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
|
||||
return result(this, obj);
|
||||
return chainResult(this, obj);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1516,7 +1574,7 @@
|
||||
_.each(['concat', 'join', 'slice'], function(name) {
|
||||
var method = ArrayProto[name];
|
||||
_.prototype[name] = function() {
|
||||
return result(this, method.apply(this._wrapped, arguments));
|
||||
return chainResult(this, method.apply(this._wrapped, arguments));
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1545,4 +1603,4 @@
|
||||
return _;
|
||||
});
|
||||
}
|
||||
}.call(this));
|
||||
}());
|
||||
|
||||
Reference in New Issue
Block a user