63 } else { |
63 } else { |
64 root._ = _; |
64 root._ = _; |
65 } |
65 } |
66 |
66 |
67 // Current version. |
67 // Current version. |
68 _.VERSION = '1.5.2'; |
68 _.VERSION = '1.6.0'; |
69 |
69 |
70 // Collection Functions |
70 // Collection Functions |
71 // -------------------- |
71 // -------------------- |
72 |
72 |
73 // The cornerstone, an `each` implementation, aka `forEach`. |
73 // The cornerstone, an `each` implementation, aka `forEach`. |
74 // Handles objects with the built-in `forEach`, arrays, and raw objects. |
74 // Handles objects with the built-in `forEach`, arrays, and raw objects. |
75 // Delegates to **ECMAScript 5**'s native `forEach` if available. |
75 // Delegates to **ECMAScript 5**'s native `forEach` if available. |
76 var each = _.each = _.forEach = function(obj, iterator, context) { |
76 var each = _.each = _.forEach = function(obj, iterator, context) { |
77 if (obj == null) return; |
77 if (obj == null) return obj; |
78 if (nativeForEach && obj.forEach === nativeForEach) { |
78 if (nativeForEach && obj.forEach === nativeForEach) { |
79 obj.forEach(iterator, context); |
79 obj.forEach(iterator, context); |
80 } else if (obj.length === +obj.length) { |
80 } else if (obj.length === +obj.length) { |
81 for (var i = 0, length = obj.length; i < length; i++) { |
81 for (var i = 0, length = obj.length; i < length; i++) { |
82 if (iterator.call(context, obj[i], i, obj) === breaker) return; |
82 if (iterator.call(context, obj[i], i, obj) === breaker) return; |
150 if (!initial) throw new TypeError(reduceError); |
151 if (!initial) throw new TypeError(reduceError); |
151 return memo; |
152 return memo; |
152 }; |
153 }; |
153 |
154 |
154 // Return the first value which passes a truth test. Aliased as `detect`. |
155 // Return the first value which passes a truth test. Aliased as `detect`. |
155 _.find = _.detect = function(obj, iterator, context) { |
156 _.find = _.detect = function(obj, predicate, context) { |
156 var result; |
157 var result; |
157 any(obj, function(value, index, list) { |
158 any(obj, function(value, index, list) { |
158 if (iterator.call(context, value, index, list)) { |
159 if (predicate.call(context, value, index, list)) { |
159 result = value; |
160 result = value; |
160 return true; |
161 return true; |
161 } |
162 } |
162 }); |
163 }); |
163 return result; |
164 return result; |
164 }; |
165 }; |
165 |
166 |
166 // Return all the elements that pass a truth test. |
167 // Return all the elements that pass a truth test. |
167 // Delegates to **ECMAScript 5**'s native `filter` if available. |
168 // Delegates to **ECMAScript 5**'s native `filter` if available. |
168 // Aliased as `select`. |
169 // Aliased as `select`. |
169 _.filter = _.select = function(obj, iterator, context) { |
170 _.filter = _.select = function(obj, predicate, context) { |
170 var results = []; |
171 var results = []; |
171 if (obj == null) return results; |
172 if (obj == null) return results; |
172 if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); |
173 if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context); |
173 each(obj, function(value, index, list) { |
174 each(obj, function(value, index, list) { |
174 if (iterator.call(context, value, index, list)) results.push(value); |
175 if (predicate.call(context, value, index, list)) results.push(value); |
175 }); |
176 }); |
176 return results; |
177 return results; |
177 }; |
178 }; |
178 |
179 |
179 // Return all the elements for which a truth test fails. |
180 // Return all the elements for which a truth test fails. |
180 _.reject = function(obj, iterator, context) { |
181 _.reject = function(obj, predicate, context) { |
181 return _.filter(obj, function(value, index, list) { |
182 return _.filter(obj, function(value, index, list) { |
182 return !iterator.call(context, value, index, list); |
183 return !predicate.call(context, value, index, list); |
183 }, context); |
184 }, context); |
184 }; |
185 }; |
185 |
186 |
186 // Determine whether all of the elements match a truth test. |
187 // Determine whether all of the elements match a truth test. |
187 // Delegates to **ECMAScript 5**'s native `every` if available. |
188 // Delegates to **ECMAScript 5**'s native `every` if available. |
188 // Aliased as `all`. |
189 // Aliased as `all`. |
189 _.every = _.all = function(obj, iterator, context) { |
190 _.every = _.all = function(obj, predicate, context) { |
190 iterator || (iterator = _.identity); |
191 predicate || (predicate = _.identity); |
191 var result = true; |
192 var result = true; |
192 if (obj == null) return result; |
193 if (obj == null) return result; |
193 if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); |
194 if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context); |
194 each(obj, function(value, index, list) { |
195 each(obj, function(value, index, list) { |
195 if (!(result = result && iterator.call(context, value, index, list))) return breaker; |
196 if (!(result = result && predicate.call(context, value, index, list))) return breaker; |
196 }); |
197 }); |
197 return !!result; |
198 return !!result; |
198 }; |
199 }; |
199 |
200 |
200 // Determine if at least one element in the object matches a truth test. |
201 // Determine if at least one element in the object matches a truth test. |
201 // Delegates to **ECMAScript 5**'s native `some` if available. |
202 // Delegates to **ECMAScript 5**'s native `some` if available. |
202 // Aliased as `any`. |
203 // Aliased as `any`. |
203 var any = _.some = _.any = function(obj, iterator, context) { |
204 var any = _.some = _.any = function(obj, predicate, context) { |
204 iterator || (iterator = _.identity); |
205 predicate || (predicate = _.identity); |
205 var result = false; |
206 var result = false; |
206 if (obj == null) return result; |
207 if (obj == null) return result; |
207 if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); |
208 if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context); |
208 each(obj, function(value, index, list) { |
209 each(obj, function(value, index, list) { |
209 if (result || (result = iterator.call(context, value, index, list))) return breaker; |
210 if (result || (result = predicate.call(context, value, index, list))) return breaker; |
210 }); |
211 }); |
211 return !!result; |
212 return !!result; |
212 }; |
213 }; |
213 |
214 |
214 // Determine if the array or object contains a given value (using `===`). |
215 // Determine if the array or object contains a given value (using `===`). |
230 }); |
231 }); |
231 }; |
232 }; |
232 |
233 |
233 // Convenience version of a common use case of `map`: fetching a property. |
234 // Convenience version of a common use case of `map`: fetching a property. |
234 _.pluck = function(obj, key) { |
235 _.pluck = function(obj, key) { |
235 return _.map(obj, function(value){ return value[key]; }); |
236 return _.map(obj, _.property(key)); |
236 }; |
237 }; |
237 |
238 |
238 // Convenience version of a common use case of `filter`: selecting only objects |
239 // Convenience version of a common use case of `filter`: selecting only objects |
239 // containing specific `key:value` pairs. |
240 // containing specific `key:value` pairs. |
240 _.where = function(obj, attrs, first) { |
241 _.where = function(obj, attrs) { |
241 if (_.isEmpty(attrs)) return first ? void 0 : []; |
242 return _.filter(obj, _.matches(attrs)); |
242 return _[first ? 'find' : 'filter'](obj, function(value) { |
|
243 for (var key in attrs) { |
|
244 if (attrs[key] !== value[key]) return false; |
|
245 } |
|
246 return true; |
|
247 }); |
|
248 }; |
243 }; |
249 |
244 |
250 // Convenience version of a common use case of `find`: getting the first object |
245 // Convenience version of a common use case of `find`: getting the first object |
251 // containing specific `key:value` pairs. |
246 // containing specific `key:value` pairs. |
252 _.findWhere = function(obj, attrs) { |
247 _.findWhere = function(obj, attrs) { |
253 return _.where(obj, attrs, true); |
248 return _.find(obj, _.matches(attrs)); |
254 }; |
249 }; |
255 |
250 |
256 // Return the maximum element or (element-based computation). |
251 // Return the maximum element or (element-based computation). |
257 // Can't optimize arrays of integers longer than 65,535 elements. |
252 // Can't optimize arrays of integers longer than 65,535 elements. |
258 // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797) |
253 // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797) |
259 _.max = function(obj, iterator, context) { |
254 _.max = function(obj, iterator, context) { |
260 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { |
255 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { |
261 return Math.max.apply(Math, obj); |
256 return Math.max.apply(Math, obj); |
262 } |
257 } |
263 if (!iterator && _.isEmpty(obj)) return -Infinity; |
258 var result = -Infinity, lastComputed = -Infinity; |
264 var result = {computed : -Infinity, value: -Infinity}; |
|
265 each(obj, function(value, index, list) { |
259 each(obj, function(value, index, list) { |
266 var computed = iterator ? iterator.call(context, value, index, list) : value; |
260 var computed = iterator ? iterator.call(context, value, index, list) : value; |
267 computed > result.computed && (result = {value : value, computed : computed}); |
261 if (computed > lastComputed) { |
268 }); |
262 result = value; |
269 return result.value; |
263 lastComputed = computed; |
|
264 } |
|
265 }); |
|
266 return result; |
270 }; |
267 }; |
271 |
268 |
272 // Return the minimum element (or element-based computation). |
269 // Return the minimum element (or element-based computation). |
273 _.min = function(obj, iterator, context) { |
270 _.min = function(obj, iterator, context) { |
274 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { |
271 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { |
275 return Math.min.apply(Math, obj); |
272 return Math.min.apply(Math, obj); |
276 } |
273 } |
277 if (!iterator && _.isEmpty(obj)) return Infinity; |
274 var result = Infinity, lastComputed = Infinity; |
278 var result = {computed : Infinity, value: Infinity}; |
|
279 each(obj, function(value, index, list) { |
275 each(obj, function(value, index, list) { |
280 var computed = iterator ? iterator.call(context, value, index, list) : value; |
276 var computed = iterator ? iterator.call(context, value, index, list) : value; |
281 computed < result.computed && (result = {value : value, computed : computed}); |
277 if (computed < lastComputed) { |
282 }); |
278 result = value; |
283 return result.value; |
279 lastComputed = computed; |
284 }; |
280 } |
285 |
281 }); |
286 // Shuffle an array, using the modern version of the |
282 return result; |
|
283 }; |
|
284 |
|
285 // Shuffle an array, using the modern version of the |
287 // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). |
286 // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). |
288 _.shuffle = function(obj) { |
287 _.shuffle = function(obj) { |
289 var rand; |
288 var rand; |
290 var index = 0; |
289 var index = 0; |
291 var shuffled = []; |
290 var shuffled = []; |
295 shuffled[rand] = value; |
294 shuffled[rand] = value; |
296 }); |
295 }); |
297 return shuffled; |
296 return shuffled; |
298 }; |
297 }; |
299 |
298 |
300 // Sample **n** random values from an array. |
299 // Sample **n** random values from a collection. |
301 // If **n** is not specified, returns a single random element from the array. |
300 // If **n** is not specified, returns a single random element. |
302 // The internal `guard` argument allows it to work with `map`. |
301 // The internal `guard` argument allows it to work with `map`. |
303 _.sample = function(obj, n, guard) { |
302 _.sample = function(obj, n, guard) { |
304 if (arguments.length < 2 || guard) { |
303 if (n == null || guard) { |
|
304 if (obj.length !== +obj.length) obj = _.values(obj); |
305 return obj[_.random(obj.length - 1)]; |
305 return obj[_.random(obj.length - 1)]; |
306 } |
306 } |
307 return _.shuffle(obj).slice(0, Math.max(0, n)); |
307 return _.shuffle(obj).slice(0, Math.max(0, n)); |
308 }; |
308 }; |
309 |
309 |
310 // An internal function to generate lookup iterators. |
310 // An internal function to generate lookup iterators. |
311 var lookupIterator = function(value) { |
311 var lookupIterator = function(value) { |
312 return _.isFunction(value) ? value : function(obj){ return obj[value]; }; |
312 if (value == null) return _.identity; |
|
313 if (_.isFunction(value)) return value; |
|
314 return _.property(value); |
313 }; |
315 }; |
314 |
316 |
315 // Sort the object's values by a criterion produced by an iterator. |
317 // Sort the object's values by a criterion produced by an iterator. |
316 _.sortBy = function(obj, value, context) { |
318 _.sortBy = function(obj, iterator, context) { |
317 var iterator = lookupIterator(value); |
319 iterator = lookupIterator(iterator); |
318 return _.pluck(_.map(obj, function(value, index, list) { |
320 return _.pluck(_.map(obj, function(value, index, list) { |
319 return { |
321 return { |
320 value: value, |
322 value: value, |
321 index: index, |
323 index: index, |
322 criteria: iterator.call(context, value, index, list) |
324 criteria: iterator.call(context, value, index, list) |
346 }; |
348 }; |
347 |
349 |
348 // Groups the object's values by a criterion. Pass either a string attribute |
350 // Groups the object's values by a criterion. Pass either a string attribute |
349 // to group by, or a function that returns the criterion. |
351 // to group by, or a function that returns the criterion. |
350 _.groupBy = group(function(result, key, value) { |
352 _.groupBy = group(function(result, key, value) { |
351 (_.has(result, key) ? result[key] : (result[key] = [])).push(value); |
353 _.has(result, key) ? result[key].push(value) : result[key] = [value]; |
352 }); |
354 }); |
353 |
355 |
354 // Indexes the object's values by a criterion, similar to `groupBy`, but for |
356 // Indexes the object's values by a criterion, similar to `groupBy`, but for |
355 // when you know that your index values will be unique. |
357 // when you know that your index values will be unique. |
356 _.indexBy = group(function(result, key, value) { |
358 _.indexBy = group(function(result, key, value) { |
365 }); |
367 }); |
366 |
368 |
367 // Use a comparator function to figure out the smallest index at which |
369 // Use a comparator function to figure out the smallest index at which |
368 // an object should be inserted so as to maintain order. Uses binary search. |
370 // an object should be inserted so as to maintain order. Uses binary search. |
369 _.sortedIndex = function(array, obj, iterator, context) { |
371 _.sortedIndex = function(array, obj, iterator, context) { |
370 iterator = iterator == null ? _.identity : lookupIterator(iterator); |
372 iterator = lookupIterator(iterator); |
371 var value = iterator.call(context, obj); |
373 var value = iterator.call(context, obj); |
372 var low = 0, high = array.length; |
374 var low = 0, high = array.length; |
373 while (low < high) { |
375 while (low < high) { |
374 var mid = (low + high) >>> 1; |
376 var mid = (low + high) >>> 1; |
375 iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; |
377 iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; |
397 // Get the first element of an array. Passing **n** will return the first N |
399 // Get the first element of an array. Passing **n** will return the first N |
398 // values in the array. Aliased as `head` and `take`. The **guard** check |
400 // values in the array. Aliased as `head` and `take`. The **guard** check |
399 // allows it to work with `_.map`. |
401 // allows it to work with `_.map`. |
400 _.first = _.head = _.take = function(array, n, guard) { |
402 _.first = _.head = _.take = function(array, n, guard) { |
401 if (array == null) return void 0; |
403 if (array == null) return void 0; |
402 return (n == null) || guard ? array[0] : slice.call(array, 0, n); |
404 if ((n == null) || guard) return array[0]; |
|
405 if (n < 0) return []; |
|
406 return slice.call(array, 0, n); |
403 }; |
407 }; |
404 |
408 |
405 // Returns everything but the last entry of the array. Especially useful on |
409 // Returns everything but the last entry of the array. Especially useful on |
406 // the arguments object. Passing **n** will return all the values in |
410 // the arguments object. Passing **n** will return all the values in |
407 // the array, excluding the last N. The **guard** check allows it to work with |
411 // the array, excluding the last N. The **guard** check allows it to work with |
412 |
416 |
413 // Get the last element of an array. Passing **n** will return the last N |
417 // Get the last element of an array. Passing **n** will return the last N |
414 // values in the array. The **guard** check allows it to work with `_.map`. |
418 // values in the array. The **guard** check allows it to work with `_.map`. |
415 _.last = function(array, n, guard) { |
419 _.last = function(array, n, guard) { |
416 if (array == null) return void 0; |
420 if (array == null) return void 0; |
417 if ((n == null) || guard) { |
421 if ((n == null) || guard) return array[array.length - 1]; |
418 return array[array.length - 1]; |
422 return slice.call(array, Math.max(array.length - n, 0)); |
419 } else { |
|
420 return slice.call(array, Math.max(array.length - n, 0)); |
|
421 } |
|
422 }; |
423 }; |
423 |
424 |
424 // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. |
425 // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. |
425 // Especially useful on the arguments object. Passing an **n** will return |
426 // Especially useful on the arguments object. Passing an **n** will return |
426 // the rest N values in the array. The **guard** |
427 // the rest N values in the array. The **guard** |
455 }; |
456 }; |
456 |
457 |
457 // Return a version of the array that does not contain the specified value(s). |
458 // Return a version of the array that does not contain the specified value(s). |
458 _.without = function(array) { |
459 _.without = function(array) { |
459 return _.difference(array, slice.call(arguments, 1)); |
460 return _.difference(array, slice.call(arguments, 1)); |
|
461 }; |
|
462 |
|
463 // Split an array into two arrays: one whose elements all satisfy the given |
|
464 // predicate, and one whose elements all do not satisfy the predicate. |
|
465 _.partition = function(array, predicate, context) { |
|
466 predicate = lookupIterator(predicate); |
|
467 var pass = [], fail = []; |
|
468 each(array, function(elem) { |
|
469 (predicate.call(context, elem) ? pass : fail).push(elem); |
|
470 }); |
|
471 return [pass, fail]; |
460 }; |
472 }; |
461 |
473 |
462 // Produce a duplicate-free version of the array. If the array has already |
474 // Produce a duplicate-free version of the array. If the array has already |
463 // been sorted, you have the option of using a faster algorithm. |
475 // been sorted, you have the option of using a faster algorithm. |
464 // Aliased as `unique`. |
476 // Aliased as `unique`. |
611 return self; |
623 return self; |
612 }; |
624 }; |
613 }; |
625 }; |
614 |
626 |
615 // Partially apply a function by creating a version that has had some of its |
627 // Partially apply a function by creating a version that has had some of its |
616 // arguments pre-filled, without changing its dynamic `this` context. |
628 // arguments pre-filled, without changing its dynamic `this` context. _ acts |
|
629 // as a placeholder, allowing any combination of arguments to be pre-filled. |
617 _.partial = function(func) { |
630 _.partial = function(func) { |
618 var args = slice.call(arguments, 1); |
631 var boundArgs = slice.call(arguments, 1); |
619 return function() { |
632 return function() { |
620 return func.apply(this, args.concat(slice.call(arguments))); |
633 var position = 0; |
621 }; |
634 var args = boundArgs.slice(); |
622 }; |
635 for (var i = 0, length = args.length; i < length; i++) { |
623 |
636 if (args[i] === _) args[i] = arguments[position++]; |
624 // Bind all of an object's methods to that object. Useful for ensuring that |
637 } |
625 // all callbacks defined on an object belong to it. |
638 while (position < arguments.length) args.push(arguments[position++]); |
|
639 return func.apply(this, args); |
|
640 }; |
|
641 }; |
|
642 |
|
643 // Bind a number of an object's methods to that object. Remaining arguments |
|
644 // are the method names to be bound. Useful for ensuring that all callbacks |
|
645 // defined on an object belong to it. |
626 _.bindAll = function(obj) { |
646 _.bindAll = function(obj) { |
627 var funcs = slice.call(arguments, 1); |
647 var funcs = slice.call(arguments, 1); |
628 if (funcs.length === 0) throw new Error("bindAll must be passed function names"); |
648 if (funcs.length === 0) throw new Error('bindAll must be passed function names'); |
629 each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); |
649 each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); |
630 return obj; |
650 return obj; |
631 }; |
651 }; |
632 |
652 |
633 // Memoize an expensive function by storing its results. |
653 // Memoize an expensive function by storing its results. |
662 var context, args, result; |
682 var context, args, result; |
663 var timeout = null; |
683 var timeout = null; |
664 var previous = 0; |
684 var previous = 0; |
665 options || (options = {}); |
685 options || (options = {}); |
666 var later = function() { |
686 var later = function() { |
667 previous = options.leading === false ? 0 : new Date; |
687 previous = options.leading === false ? 0 : _.now(); |
668 timeout = null; |
688 timeout = null; |
669 result = func.apply(context, args); |
689 result = func.apply(context, args); |
|
690 context = args = null; |
670 }; |
691 }; |
671 return function() { |
692 return function() { |
672 var now = new Date; |
693 var now = _.now(); |
673 if (!previous && options.leading === false) previous = now; |
694 if (!previous && options.leading === false) previous = now; |
674 var remaining = wait - (now - previous); |
695 var remaining = wait - (now - previous); |
675 context = this; |
696 context = this; |
676 args = arguments; |
697 args = arguments; |
677 if (remaining <= 0) { |
698 if (remaining <= 0) { |
678 clearTimeout(timeout); |
699 clearTimeout(timeout); |
679 timeout = null; |
700 timeout = null; |
680 previous = now; |
701 previous = now; |
681 result = func.apply(context, args); |
702 result = func.apply(context, args); |
|
703 context = args = null; |
682 } else if (!timeout && options.trailing !== false) { |
704 } else if (!timeout && options.trailing !== false) { |
683 timeout = setTimeout(later, remaining); |
705 timeout = setTimeout(later, remaining); |
684 } |
706 } |
685 return result; |
707 return result; |
686 }; |
708 }; |
690 // be triggered. The function will be called after it stops being called for |
712 // be triggered. The function will be called after it stops being called for |
691 // N milliseconds. If `immediate` is passed, trigger the function on the |
713 // N milliseconds. If `immediate` is passed, trigger the function on the |
692 // leading edge, instead of the trailing. |
714 // leading edge, instead of the trailing. |
693 _.debounce = function(func, wait, immediate) { |
715 _.debounce = function(func, wait, immediate) { |
694 var timeout, args, context, timestamp, result; |
716 var timeout, args, context, timestamp, result; |
|
717 |
|
718 var later = function() { |
|
719 var last = _.now() - timestamp; |
|
720 if (last < wait) { |
|
721 timeout = setTimeout(later, wait - last); |
|
722 } else { |
|
723 timeout = null; |
|
724 if (!immediate) { |
|
725 result = func.apply(context, args); |
|
726 context = args = null; |
|
727 } |
|
728 } |
|
729 }; |
|
730 |
695 return function() { |
731 return function() { |
696 context = this; |
732 context = this; |
697 args = arguments; |
733 args = arguments; |
698 timestamp = new Date(); |
734 timestamp = _.now(); |
699 var later = function() { |
|
700 var last = (new Date()) - timestamp; |
|
701 if (last < wait) { |
|
702 timeout = setTimeout(later, wait - last); |
|
703 } else { |
|
704 timeout = null; |
|
705 if (!immediate) result = func.apply(context, args); |
|
706 } |
|
707 }; |
|
708 var callNow = immediate && !timeout; |
735 var callNow = immediate && !timeout; |
709 if (!timeout) { |
736 if (!timeout) { |
710 timeout = setTimeout(later, wait); |
737 timeout = setTimeout(later, wait); |
711 } |
738 } |
712 if (callNow) result = func.apply(context, args); |
739 if (callNow) { |
|
740 result = func.apply(context, args); |
|
741 context = args = null; |
|
742 } |
|
743 |
713 return result; |
744 return result; |
714 }; |
745 }; |
715 }; |
746 }; |
716 |
747 |
717 // Returns a function that will be executed at most one time, no matter how |
748 // Returns a function that will be executed at most one time, no matter how |
729 |
760 |
730 // Returns the first function passed as an argument to the second, |
761 // Returns the first function passed as an argument to the second, |
731 // allowing you to adjust arguments, run code before and after, and |
762 // allowing you to adjust arguments, run code before and after, and |
732 // conditionally execute the original function. |
763 // conditionally execute the original function. |
733 _.wrap = function(func, wrapper) { |
764 _.wrap = function(func, wrapper) { |
734 return function() { |
765 return _.partial(wrapper, func); |
735 var args = [func]; |
|
736 push.apply(args, arguments); |
|
737 return wrapper.apply(this, args); |
|
738 }; |
|
739 }; |
766 }; |
740 |
767 |
741 // Returns a function that is the composition of a list of functions, each |
768 // Returns a function that is the composition of a list of functions, each |
742 // consuming the return value of the function that follows. |
769 // consuming the return value of the function that follows. |
743 _.compose = function() { |
770 _.compose = function() { |
1059 // Keep the identity function around for default iterators. |
1088 // Keep the identity function around for default iterators. |
1060 _.identity = function(value) { |
1089 _.identity = function(value) { |
1061 return value; |
1090 return value; |
1062 }; |
1091 }; |
1063 |
1092 |
|
1093 _.constant = function(value) { |
|
1094 return function () { |
|
1095 return value; |
|
1096 }; |
|
1097 }; |
|
1098 |
|
1099 _.property = function(key) { |
|
1100 return function(obj) { |
|
1101 return obj[key]; |
|
1102 }; |
|
1103 }; |
|
1104 |
|
1105 // Returns a predicate for checking whether an object has a given set of `key:value` pairs. |
|
1106 _.matches = function(attrs) { |
|
1107 return function(obj) { |
|
1108 if (obj === attrs) return true; //avoid comparing an object to itself. |
|
1109 for (var key in attrs) { |
|
1110 if (attrs[key] !== obj[key]) |
|
1111 return false; |
|
1112 } |
|
1113 return true; |
|
1114 } |
|
1115 }; |
|
1116 |
1064 // Run a function **n** times. |
1117 // Run a function **n** times. |
1065 _.times = function(n, iterator, context) { |
1118 _.times = function(n, iterator, context) { |
1066 var accum = Array(Math.max(0, n)); |
1119 var accum = Array(Math.max(0, n)); |
1067 for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i); |
1120 for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i); |
1068 return accum; |
1121 return accum; |