mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-11 11:27:50 +00:00
Update vendor/underscore and underscore tests.
This commit is contained in:
330
vendor/underscore/underscore.js
vendored
330
vendor/underscore/underscore.js
vendored
@@ -31,15 +31,6 @@
|
||||
// All **ECMAScript 5** native function implementations that we hope to use
|
||||
// are declared here.
|
||||
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;
|
||||
@@ -71,13 +62,11 @@
|
||||
// --------------------
|
||||
|
||||
// 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.
|
||||
var each = _.each = _.forEach = function(obj, iterator, context) {
|
||||
// Handles raw objects in addition to array-likes. Treats all
|
||||
// sparse array-likes as if they were dense.
|
||||
_.each = _.forEach = function(obj, iterator, context) {
|
||||
if (obj == null) return obj;
|
||||
if (nativeForEach && obj.forEach === nativeForEach) {
|
||||
obj.forEach(iterator, context);
|
||||
} else if (obj.length === +obj.length) {
|
||||
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;
|
||||
}
|
||||
@@ -91,12 +80,10 @@
|
||||
};
|
||||
|
||||
// Return the results of applying the iterator to each element.
|
||||
// Delegates to **ECMAScript 5**'s native `map` if available.
|
||||
_.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) {
|
||||
_.each(obj, function(value, index, list) {
|
||||
results.push(iterator.call(context, value, index, list));
|
||||
});
|
||||
return results;
|
||||
@@ -105,15 +92,11 @@
|
||||
var reduceError = 'Reduce of empty array with no initial value';
|
||||
|
||||
// **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;
|
||||
if (obj == null) obj = [];
|
||||
if (nativeReduce && obj.reduce === nativeReduce) {
|
||||
if (context) iterator = _.bind(iterator, context);
|
||||
return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
|
||||
}
|
||||
each(obj, function(value, index, list) {
|
||||
_.each(obj, function(value, index, list) {
|
||||
if (!initial) {
|
||||
memo = value;
|
||||
initial = true;
|
||||
@@ -126,20 +109,15 @@
|
||||
};
|
||||
|
||||
// The right-associative version of reduce, also known as `foldr`.
|
||||
// Delegates to **ECMAScript 5**'s native `reduceRight` if available.
|
||||
_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
|
||||
var initial = arguments.length > 2;
|
||||
if (obj == null) obj = [];
|
||||
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
|
||||
if (context) iterator = _.bind(iterator, context);
|
||||
return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
|
||||
}
|
||||
var length = obj.length;
|
||||
if (length !== +length) {
|
||||
var keys = _.keys(obj);
|
||||
length = keys.length;
|
||||
}
|
||||
each(obj, function(value, index, list) {
|
||||
_.each(obj, function(value, index, list) {
|
||||
index = keys ? keys[--length] : --length;
|
||||
if (!initial) {
|
||||
memo = obj[index];
|
||||
@@ -155,7 +133,7 @@
|
||||
// Return the first value which passes a truth test. Aliased as `detect`.
|
||||
_.find = _.detect = function(obj, predicate, context) {
|
||||
var result;
|
||||
any(obj, function(value, index, list) {
|
||||
_.some(obj, function(value, index, list) {
|
||||
if (predicate.call(context, value, index, list)) {
|
||||
result = value;
|
||||
return true;
|
||||
@@ -165,13 +143,11 @@
|
||||
};
|
||||
|
||||
// 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) {
|
||||
var results = [];
|
||||
if (obj == null) return results;
|
||||
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context);
|
||||
each(obj, function(value, index, list) {
|
||||
_.each(obj, function(value, index, list) {
|
||||
if (predicate.call(context, value, index, list)) results.push(value);
|
||||
});
|
||||
return results;
|
||||
@@ -179,34 +155,28 @@
|
||||
|
||||
// Return all the elements for which a truth test fails.
|
||||
_.reject = function(obj, predicate, context) {
|
||||
return _.filter(obj, function(value, index, list) {
|
||||
return !predicate.call(context, value, index, list);
|
||||
}, context);
|
||||
return _.filter(obj, _.negate(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) {
|
||||
_.each(obj, function(value, index, list) {
|
||||
if (!(result = result && predicate.call(context, value, index, list))) return breaker;
|
||||
});
|
||||
return !!result;
|
||||
};
|
||||
|
||||
// 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) {
|
||||
_.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) {
|
||||
_.each(obj, function(value, index, list) {
|
||||
if (result || (result = predicate.call(context, value, index, list))) return breaker;
|
||||
});
|
||||
return !!result;
|
||||
@@ -216,8 +186,8 @@
|
||||
// Aliased as `include`.
|
||||
_.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) {
|
||||
if (obj.length === +obj.length) return _.indexOf(obj, target) >= 0;
|
||||
return _.some(obj, function(value) {
|
||||
return value === target;
|
||||
});
|
||||
};
|
||||
@@ -249,36 +219,48 @@
|
||||
};
|
||||
|
||||
// Return the maximum element or (element-based computation).
|
||||
// Can't optimize arrays of integers longer than 65,535 elements.
|
||||
// See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
|
||||
_.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;
|
||||
var result = -Infinity, lastComputed = -Infinity,
|
||||
value, computed;
|
||||
if (!iterator && _.isArray(obj)) {
|
||||
for (var i = 0, length = obj.length; i < length; i++) {
|
||||
value = obj[i];
|
||||
if (value > result) {
|
||||
result = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
_.each(obj, function(value, index, list) {
|
||||
computed = iterator ? iterator.call(context, value, index, list) : value;
|
||||
if (computed > lastComputed) {
|
||||
result = value;
|
||||
lastComputed = computed;
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// Return the minimum element (or element-based computation).
|
||||
_.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;
|
||||
var result = Infinity, lastComputed = Infinity,
|
||||
value, computed;
|
||||
if (!iterator && _.isArray(obj)) {
|
||||
for (var i = 0, length = obj.length; i < length; i++) {
|
||||
value = obj[i];
|
||||
if (value < result) {
|
||||
result = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
_.each(obj, function(value, index, list) {
|
||||
computed = iterator ? iterator.call(context, value, index, list) : value;
|
||||
if (computed < lastComputed) {
|
||||
result = value;
|
||||
lastComputed = computed;
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -288,7 +270,7 @@
|
||||
var rand;
|
||||
var index = 0;
|
||||
var shuffled = [];
|
||||
each(obj, function(value) {
|
||||
_.each(obj, function(value) {
|
||||
rand = _.random(index++);
|
||||
shuffled[index - 1] = shuffled[rand];
|
||||
shuffled[rand] = value;
|
||||
@@ -308,20 +290,23 @@
|
||||
};
|
||||
|
||||
// An internal function to generate lookup iterators.
|
||||
var lookupIterator = function(value) {
|
||||
var lookupIterator = function(value, context) {
|
||||
if (value == null) return _.identity;
|
||||
if (_.isFunction(value)) return value;
|
||||
return _.property(value);
|
||||
if (!_.isFunction(value)) return _.property(value);
|
||||
if (!context) return value;
|
||||
return function() {
|
||||
return value.apply(context, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
// Sort the object's values by a criterion produced by an iterator.
|
||||
_.sortBy = function(obj, iterator, context) {
|
||||
iterator = lookupIterator(iterator);
|
||||
iterator = lookupIterator(iterator, context);
|
||||
return _.pluck(_.map(obj, function(value, index, list) {
|
||||
return {
|
||||
value: value,
|
||||
index: index,
|
||||
criteria: iterator.call(context, value, index, list)
|
||||
criteria: iterator(value, index, list)
|
||||
};
|
||||
}).sort(function(left, right) {
|
||||
var a = left.criteria;
|
||||
@@ -338,9 +323,9 @@
|
||||
var group = function(behavior) {
|
||||
return function(obj, iterator, context) {
|
||||
var result = {};
|
||||
iterator = lookupIterator(iterator);
|
||||
each(obj, function(value, index) {
|
||||
var key = iterator.call(context, value, index, obj);
|
||||
iterator = lookupIterator(iterator, context);
|
||||
_.each(obj, function(value, index) {
|
||||
var key = iterator(value, index, obj);
|
||||
behavior(result, key, value);
|
||||
});
|
||||
return result;
|
||||
@@ -369,12 +354,12 @@
|
||||
// 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, iterator, context) {
|
||||
iterator = lookupIterator(iterator);
|
||||
var value = iterator.call(context, obj);
|
||||
iterator = lookupIterator(iterator, context);
|
||||
var value = iterator(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;
|
||||
iterator(array[mid]) < value ? low = mid + 1 : high = mid;
|
||||
}
|
||||
return low;
|
||||
};
|
||||
@@ -411,7 +396,7 @@
|
||||
// the array, excluding the last N. The **guard** check allows it to work with
|
||||
// `_.map`.
|
||||
_.initial = function(array, n, guard) {
|
||||
return slice.call(array, 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
|
||||
@@ -436,23 +421,26 @@
|
||||
};
|
||||
|
||||
// Internal implementation of a recursive `flatten` function.
|
||||
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 out an array, either recursively (by default), or just one level.
|
||||
_.flatten = function(array, shallow) {
|
||||
return flatten(array, shallow, []);
|
||||
return flatten(array, shallow, false, []);
|
||||
};
|
||||
|
||||
// Return a version of the array that does not contain the specified value(s).
|
||||
@@ -462,9 +450,10 @@
|
||||
|
||||
// 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) {
|
||||
_.partition = function(obj, predicate, context) {
|
||||
predicate = lookupIterator(predicate, context);
|
||||
var pass = [], fail = [];
|
||||
each(array, function(elem) {
|
||||
_.each(obj, function(elem) {
|
||||
(predicate(elem) ? pass : fail).push(elem);
|
||||
});
|
||||
return [pass, fail];
|
||||
@@ -474,44 +463,53 @@
|
||||
// been sorted, you have the option of using a faster algorithm.
|
||||
// Aliased as `unique`.
|
||||
_.uniq = _.unique = function(array, isSorted, iterator, context) {
|
||||
if (array == null) return [];
|
||||
if (_.isFunction(isSorted)) {
|
||||
context = iterator;
|
||||
iterator = isSorted;
|
||||
isSorted = false;
|
||||
}
|
||||
var initial = iterator ? _.map(array, iterator, context) : array;
|
||||
var results = [];
|
||||
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 (iterator) value = iterator.call(context, value, i, array);
|
||||
if (isSorted ? (!i || seen !== value) : !_.contains(seen, value)) {
|
||||
if (isSorted) seen = value;
|
||||
else seen.push(value);
|
||||
result.push(array[i]);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// Produce an array that contains the union: each distinct element from all of
|
||||
// the passed-in arrays.
|
||||
_.union = function() {
|
||||
return _.uniq(_.flatten(arguments, true));
|
||||
return _.uniq(flatten(arguments, true, true, []));
|
||||
};
|
||||
|
||||
// Produce an array that contains every item shared between all the
|
||||
// passed-in arrays.
|
||||
_.intersection = function(array) {
|
||||
var rest = slice.call(arguments, 1);
|
||||
return _.filter(_.uniq(array), function(item) {
|
||||
return _.every(rest, function(other) {
|
||||
return _.contains(other, item);
|
||||
});
|
||||
});
|
||||
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;
|
||||
};
|
||||
|
||||
// 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 = concat.apply(ArrayProto, slice.call(arguments, 1));
|
||||
var rest = flatten(slice.call(arguments, 1), true, true, []);
|
||||
return _.filter(array, function(value){ return !_.contains(rest, value); });
|
||||
};
|
||||
|
||||
@@ -542,10 +540,8 @@
|
||||
return result;
|
||||
};
|
||||
|
||||
// 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) {
|
||||
@@ -559,19 +555,13 @@
|
||||
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) {
|
||||
if (array == null) return -1;
|
||||
var hasIndex = from != null;
|
||||
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
|
||||
return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
|
||||
}
|
||||
var i = (hasIndex ? from : array.length);
|
||||
var i = from == null ? array.length : from;
|
||||
while (i--) if (array[i] === item) return i;
|
||||
return -1;
|
||||
};
|
||||
@@ -645,7 +635,7 @@
|
||||
_.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); });
|
||||
_.each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
|
||||
return obj;
|
||||
};
|
||||
|
||||
@@ -694,7 +684,7 @@
|
||||
var remaining = wait - (now - previous);
|
||||
context = this;
|
||||
args = arguments;
|
||||
if (remaining <= 0) {
|
||||
if (remaining <= 0 || remaining > wait) {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
previous = now;
|
||||
@@ -716,7 +706,8 @@
|
||||
|
||||
var later = function() {
|
||||
var last = _.now() - timestamp;
|
||||
if (last < wait) {
|
||||
|
||||
if (last < wait && last > 0) {
|
||||
timeout = setTimeout(later, wait - last);
|
||||
} else {
|
||||
timeout = null;
|
||||
@@ -764,6 +755,13 @@
|
||||
return _.partial(wrapper, func);
|
||||
};
|
||||
|
||||
// Returns a negated version of the passed-in predicate.
|
||||
_.negate = function(predicate) {
|
||||
return function() {
|
||||
return !predicate.apply(this, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
// Returns a function that is the composition of a list of functions, each
|
||||
// consuming the return value of the function that follows.
|
||||
_.compose = function() {
|
||||
@@ -843,7 +841,7 @@
|
||||
|
||||
// Extend a given object with all the properties in passed-in object(s).
|
||||
_.extend = function(obj) {
|
||||
each(slice.call(arguments, 1), function(source) {
|
||||
_.each(slice.call(arguments, 1), function(source) {
|
||||
if (source) {
|
||||
for (var prop in source) {
|
||||
obj[prop] = source[prop];
|
||||
@@ -854,28 +852,38 @@
|
||||
};
|
||||
|
||||
// Return a copy of the object only containing the whitelisted properties.
|
||||
_.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, iterator, context) {
|
||||
var result = {};
|
||||
if (_.isFunction(iterator)) {
|
||||
for (var key in obj) {
|
||||
var value = obj[key];
|
||||
if (iterator.call(context, value, key, obj)) result[key] = value;
|
||||
}
|
||||
} else {
|
||||
var keys = concat.apply([], slice.call(arguments, 1));
|
||||
for (var i = 0, length = keys.length; i < length; i++) {
|
||||
var key = keys[i];
|
||||
if (key in obj) result[key] = obj[key];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// Return a copy of the object without the blacklisted properties.
|
||||
_.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, iterator, context) {
|
||||
var keys;
|
||||
if (_.isFunction(iterator)) {
|
||||
iterator = _.negate(iterator);
|
||||
} else {
|
||||
keys = _.map(concat.apply([], slice.call(arguments, 1)), String);
|
||||
iterator = function(value, key) { return !_.contains(keys, key); };
|
||||
}
|
||||
return copy;
|
||||
return _.pick(obj, iterator, context);
|
||||
};
|
||||
|
||||
// Fill in a given object with default properties.
|
||||
_.defaults = function(obj) {
|
||||
each(slice.call(arguments, 1), function(source) {
|
||||
_.each(slice.call(arguments, 1), function(source) {
|
||||
if (source) {
|
||||
for (var prop in source) {
|
||||
if (obj[prop] === void 0) obj[prop] = source[prop];
|
||||
@@ -1000,7 +1008,7 @@
|
||||
// An "empty" object has no enumerable own-properties.
|
||||
_.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;
|
||||
};
|
||||
@@ -1022,7 +1030,7 @@
|
||||
};
|
||||
|
||||
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
|
||||
each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
|
||||
_.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
|
||||
_['is' + name] = function(obj) {
|
||||
return toString.call(obj) == '[object ' + name + ']';
|
||||
};
|
||||
@@ -1090,11 +1098,13 @@
|
||||
};
|
||||
|
||||
_.constant = function(value) {
|
||||
return function () {
|
||||
return function() {
|
||||
return value;
|
||||
};
|
||||
};
|
||||
|
||||
_.noop = function(){};
|
||||
|
||||
_.property = function(key) {
|
||||
return function(obj) {
|
||||
return obj[key];
|
||||
@@ -1104,11 +1114,9 @@
|
||||
// Returns a predicate for checking whether an object has a given set of `key:value` pairs.
|
||||
_.matches = function(attrs) {
|
||||
return function(obj) {
|
||||
if (obj === attrs) return true; //avoid comparing an object to itself.
|
||||
for (var key in attrs) {
|
||||
if (attrs[key] !== obj[key])
|
||||
return false;
|
||||
}
|
||||
if (obj == null) return _.isEmpty(attrs);
|
||||
if (obj === attrs) return true;
|
||||
for (var key in attrs) if (attrs[key] !== obj[key]) return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -1165,12 +1173,12 @@
|
||||
_.result = function(object, property) {
|
||||
if (object == null) return void 0;
|
||||
var value = object[property];
|
||||
return _.isFunction(value) ? value.call(object) : value;
|
||||
return _.isFunction(value) ? object[property]() : value;
|
||||
};
|
||||
|
||||
// Add your own custom functions to the Underscore object.
|
||||
_.mixin = function(obj) {
|
||||
each(_.functions(obj), function(name) {
|
||||
_.each(_.functions(obj), function(name) {
|
||||
var func = _[name] = obj[name];
|
||||
_.prototype[name] = function() {
|
||||
var args = [this._wrapped];
|
||||
@@ -1208,18 +1216,20 @@
|
||||
'\\': '\\',
|
||||
'\r': 'r',
|
||||
'\n': 'n',
|
||||
'\t': 't',
|
||||
'\u2028': 'u2028',
|
||||
'\u2029': 'u2029'
|
||||
};
|
||||
|
||||
var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
|
||||
var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
|
||||
|
||||
var escapeChar = function(match) {
|
||||
return '\\' + escapes[match];
|
||||
};
|
||||
|
||||
// JavaScript micro-templating, similar to John Resig's implementation.
|
||||
// Underscore templating handles arbitrary delimiters, preserves whitespace,
|
||||
// and correctly escapes quotes within interpolated code.
|
||||
_.template = function(text, data, settings) {
|
||||
var render;
|
||||
settings = _.defaults({}, settings, _.templateSettings);
|
||||
|
||||
// Combine delimiters into one regular expression via alternation.
|
||||
@@ -1233,19 +1243,18 @@
|
||||
var index = 0;
|
||||
var source = "__p+='";
|
||||
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
|
||||
source += text.slice(index, offset)
|
||||
.replace(escaper, function(match) { return '\\' + escapes[match]; });
|
||||
source += text.slice(index, offset).replace(escaper, escapeChar);
|
||||
index = offset + match.length;
|
||||
|
||||
if (escape) {
|
||||
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
|
||||
}
|
||||
if (interpolate) {
|
||||
} else if (interpolate) {
|
||||
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
|
||||
}
|
||||
if (evaluate) {
|
||||
} else if (evaluate) {
|
||||
source += "';\n" + evaluate + "\n__p+='";
|
||||
}
|
||||
index = offset + match.length;
|
||||
|
||||
// Adobe VMs need the match returned to produce the correct offest.
|
||||
return match;
|
||||
});
|
||||
source += "';\n";
|
||||
@@ -1258,7 +1267,7 @@
|
||||
source + "return __p;\n";
|
||||
|
||||
try {
|
||||
render = new Function(settings.variable || 'obj', '_', source);
|
||||
var render = new Function(settings.variable || 'obj', '_', source);
|
||||
} catch (e) {
|
||||
e.source = source;
|
||||
throw e;
|
||||
@@ -1269,8 +1278,9 @@
|
||||
return render.call(this, data, _);
|
||||
};
|
||||
|
||||
// Provide the compiled function source as a convenience for precompilation.
|
||||
template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
|
||||
// Provide the compiled source as a convenience for precompilation.
|
||||
var argument = settings.variable || 'obj';
|
||||
template.source = 'function(' + argument + '){\n' + source + '}';
|
||||
|
||||
return template;
|
||||
};
|
||||
@@ -1295,7 +1305,7 @@
|
||||
_.mixin(_);
|
||||
|
||||
// Add all mutator Array functions to the wrapper.
|
||||
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
||||
_.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
||||
var method = ArrayProto[name];
|
||||
_.prototype[name] = function() {
|
||||
var obj = this._wrapped;
|
||||
@@ -1306,7 +1316,7 @@
|
||||
});
|
||||
|
||||
// Add all accessor Array functions to the wrapper.
|
||||
each(['concat', 'join', 'slice'], function(name) {
|
||||
_.each(['concat', 'join', 'slice'], function(name) {
|
||||
var method = ArrayProto[name];
|
||||
_.prototype[name] = function() {
|
||||
return result.call(this, method.apply(this._wrapped, arguments));
|
||||
|
||||
Reference in New Issue
Block a user