Código fuente de WordPress - trunk (underscore-1.4.4.js)

1	//     Underscore.js 1.4.4
2	//     http://underscorejs.org
3	//     (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
4	//     Underscore may be freely distributed under the MIT license.
5	
6	(function() {
7	
8	  // Baseline setup
9	  // --------------
10	
11	  // Establish the root object, `window` in the browser, or `global` on the server.
12	  var root = this;
13	
14	  // Save the previous value of the `_` variable.
15	  var previousUnderscore = root._;
16	
17	  // Establish the object that gets returned to break out of a loop iteration.
18	  var breaker = {};
19	
20	  // Save bytes in the minified (but not gzipped) version:
21	  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
22	
23	  // Create quick reference variables for speed access to core prototypes.
24	  var push             = ArrayProto.push,
25	      slice            = ArrayProto.slice,
26	      concat           = ArrayProto.concat,
27	      toString         = ObjProto.toString,
28	      hasOwnProperty   = ObjProto.hasOwnProperty;
29	
30	  // All **ECMAScript 5** native function implementations that we hope to use
31	  // are declared here.
32	  var
33	    nativeForEach      = ArrayProto.forEach,
34	    nativeMap          = ArrayProto.map,
35	    nativeReduce       = ArrayProto.reduce,
36	    nativeReduceRight  = ArrayProto.reduceRight,
37	    nativeFilter       = ArrayProto.filter,
38	    nativeEvery        = ArrayProto.every,
39	    nativeSome         = ArrayProto.some,
40	    nativeIndexOf      = ArrayProto.indexOf,
41	    nativeLastIndexOf  = ArrayProto.lastIndexOf,
42	    nativeIsArray      = Array.isArray,
43	    nativeKeys         = Object.keys,
44	    nativeBind         = FuncProto.bind;
45	
46	  // Create a safe reference to the Underscore object for use below.
47	  var _ = function(obj) {
48	    if (obj instanceof _) return obj;
49	    if (!(this instanceof _)) return new _(obj);
50	    this._wrapped = obj;
51	  };
52	
53	  // Export the Underscore object for **Node.js**, with
54	  // backwards-compatibility for the old `require()` API. If we're in
55	  // the browser, add `_` as a global object via a string identifier,
56	  // for Closure Compiler "advanced" mode.
57	  if (typeof exports !== 'undefined') {
58	    if (typeof module !== 'undefined' && module.exports) {
59	      exports = module.exports = _;
60	    }
61	    exports._ = _;
62	  } else {
63	    root._ = _;
64	  }
65	
66	  // Current version.
67	  _.VERSION = '1.4.4';
68	
69	  // Collection Functions
70	  // --------------------
71	
72	  // The cornerstone, an `each` implementation, aka `forEach`.
73	  // Handles objects with the built-in `forEach`, arrays, and raw objects.
74	  // Delegates to **ECMAScript 5**'s native `forEach` if available.
75	  var each = _.each = _.forEach = function(obj, iterator, context) {
76	    if (obj == null) return;
77	    if (nativeForEach && obj.forEach === nativeForEach) {
78	      obj.forEach(iterator, context);
79	    } else if (obj.length === +obj.length) {
80	      for (var i = 0, l = obj.length; i < l; i++) {
81	        if (iterator.call(context, obj[i], i, obj) === breaker) return;
82	      }
83	    } else {
84	      for (var key in obj) {
85	        if (_.has(obj, key)) {
86	          if (iterator.call(context, obj[key], key, obj) === breaker) return;
87	        }
88	      }
89	    }
90	  };
91	
92	  // Return the results of applying the iterator to each element.
93	  // Delegates to **ECMAScript 5**'s native `map` if available.
94	  _.map = _.collect = function(obj, iterator, context) {
95	    var results = [];
96	    if (obj == null) return results;
97	    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
98	    each(obj, function(value, index, list) {
99	      results[results.length] = iterator.call(context, value, index, list);
100	    });
101	    return results;
102	  };
103	
104	  var reduceError = 'Reduce of empty array with no initial value';
105	
106	  // **Reduce** builds up a single result from a list of values, aka `inject`,
107	  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
108	  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
109	    var initial = arguments.length > 2;
110	    if (obj == null) obj = [];
111	    if (nativeReduce && obj.reduce === nativeReduce) {
112	      if (context) iterator = _.bind(iterator, context);
113	      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
114	    }
115	    each(obj, function(value, index, list) {
116	      if (!initial) {
117	        memo = value;
118	        initial = true;
119	      } else {
120	        memo = iterator.call(context, memo, value, index, list);
121	      }
122	    });
123	    if (!initial) throw new TypeError(reduceError);
124	    return memo;
125	  };
126	
127	  // The right-associative version of reduce, also known as `foldr`.
128	  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
129	  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
130	    var initial = arguments.length > 2;
131	    if (obj == null) obj = [];
132	    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
133	      if (context) iterator = _.bind(iterator, context);
134	      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
135	    }
136	    var length = obj.length;
137	    if (length !== +length) {
138	      var keys = _.keys(obj);
139	      length = keys.length;
140	    }
141	    each(obj, function(value, index, list) {
142	      index = keys ? keys[--length] : --length;
143	      if (!initial) {
144	        memo = obj[index];
145	        initial = true;
146	      } else {
147	        memo = iterator.call(context, memo, obj[index], index, list);
148	      }
149	    });
150	    if (!initial) throw new TypeError(reduceError);
151	    return memo;
152	  };
153	
154	  // Return the first value which passes a truth test. Aliased as `detect`.
155	  _.find = _.detect = function(obj, iterator, context) {
156	    var result;
157	    any(obj, function(value, index, list) {
158	      if (iterator.call(context, value, index, list)) {
159	        result = value;
160	        return true;
161	      }
162	    });
163	    return result;
164	  };
165	
166	  // Return all the elements that pass a truth test.
167	  // Delegates to **ECMAScript 5**'s native `filter` if available.
168	  // Aliased as `select`.
169	  _.filter = _.select = function(obj, iterator, context) {
170	    var results = [];
171	    if (obj == null) return results;
172	    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
173	    each(obj, function(value, index, list) {
174	      if (iterator.call(context, value, index, list)) results[results.length] = value;
175	    });
176	    return results;
177	  };
178	
179	  // Return all the elements for which a truth test fails.
180	  _.reject = function(obj, iterator, context) {
181	    return _.filter(obj, function(value, index, list) {
182	      return !iterator.call(context, value, index, list);
183	    }, context);
184	  };
185	
186	  // Determine whether all of the elements match a truth test.
187	  // Delegates to **ECMAScript 5**'s native `every` if available.
188	  // Aliased as `all`.
189	  _.every = _.all = function(obj, iterator, context) {
190	    iterator || (iterator = _.identity);
191	    var result = true;
192	    if (obj == null) return result;
193	    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
194	    each(obj, function(value, index, list) {
195	      if (!(result = result && iterator.call(context, value, index, list))) return breaker;
196	    });
197	    return !!result;
198	  };
199	
200	  // Determine if at least one element in the object matches a truth test.
201	  // Delegates to **ECMAScript 5**'s native `some` if available.
202	  // Aliased as `any`.
203	  var any = _.some = _.any = function(obj, iterator, context) {
204	    iterator || (iterator = _.identity);
205	    var result = false;
206	    if (obj == null) return result;
207	    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
208	    each(obj, function(value, index, list) {
209	      if (result || (result = iterator.call(context, value, index, list))) return breaker;
210	    });
211	    return !!result;
212	  };
213	
214	  // Determine if the array or object contains a given value (using `===`).
215	  // Aliased as `include`.
216	  _.contains = _.include = function(obj, target) {
217	    if (obj == null) return false;
218	    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
219	    return any(obj, function(value) {
220	      return value === target;
221	    });
222	  };
223	
224	  // Invoke a method (with arguments) on every item in a collection.
225	  _.invoke = function(obj, method) {
226	    var args = slice.call(arguments, 2);
227	    var isFunc = _.isFunction(method);
228	    return _.map(obj, function(value) {
229	      return (isFunc ? method : value[method]).apply(value, args);
230	    });
231	  };
232	
233	  // Convenience version of a common use case of `map`: fetching a property.
234	  _.pluck = function(obj, key) {
235	    return _.map(obj, function(value){ return value[key]; });
236	  };
237	
238	  // Convenience version of a common use case of `filter`: selecting only objects
239	  // containing specific `key:value` pairs.
240	  _.where = function(obj, attrs, first) {
241	    if (_.isEmpty(attrs)) return first ? null : [];
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	  };
249	
250	  // Convenience version of a common use case of `find`: getting the first object
251	  // containing specific `key:value` pairs.
252	  _.findWhere = function(obj, attrs) {
253	    return _.where(obj, attrs, true);
254	  };
255	
256	  // Return the maximum element or (element-based computation).
257	  // Can't optimize arrays of integers longer than 65,535 elements.
258	  // See: https://bugs.webkit.org/show_bug.cgi?id=80797
259	  _.max = function(obj, iterator, context) {
260	    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
261	      return Math.max.apply(Math, obj);
262	    }
263	    if (!iterator && _.isEmpty(obj)) return -Infinity;
264	    var result = {computed : -Infinity, value: -Infinity};
265	    each(obj, function(value, index, list) {
266	      var computed = iterator ? iterator.call(context, value, index, list) : value;
267	      computed >= result.computed && (result = {value : value, computed : computed});
268	    });
269	    return result.value;
270	  };
271	
272	  // Return the minimum element (or element-based computation).
273	  _.min = function(obj, iterator, context) {
274	    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
275	      return Math.min.apply(Math, obj);
276	    }
277	    if (!iterator && _.isEmpty(obj)) return Infinity;
278	    var result = {computed : Infinity, value: Infinity};
279	    each(obj, function(value, index, list) {
280	      var computed = iterator ? iterator.call(context, value, index, list) : value;
281	      computed < result.computed && (result = {value : value, computed : computed});
282	    });
283	    return result.value;
284	  };
285	
286	  // Shuffle an array.
287	  _.shuffle = function(obj) {
288	    var rand;
289	    var index = 0;
290	    var shuffled = [];
291	    each(obj, function(value) {
292	      rand = _.random(index++);
293	      shuffled[index - 1] = shuffled[rand];
294	      shuffled[rand] = value;
295	    });
296	    return shuffled;
297	  };
298	
299	  // An internal function to generate lookup iterators.
300	  var lookupIterator = function(value) {
301	    return _.isFunction(value) ? value : function(obj){ return obj[value]; };
302	  };
303	
304	  // Sort the object's values by a criterion produced by an iterator.
305	  _.sortBy = function(obj, value, context) {
306	    var iterator = lookupIterator(value);
307	    return _.pluck(_.map(obj, function(value, index, list) {
308	      return {
309	        value : value,
310	        index : index,
311	        criteria : iterator.call(context, value, index, list)
312	      };
313	    }).sort(function(left, right) {
314	      var a = left.criteria;
315	      var b = right.criteria;
316	      if (a !== b) {
317	        if (a > b || a === void 0) return 1;
318	        if (a < b || b === void 0) return -1;
319	      }
320	      return left.index < right.index ? -1 : 1;
321	    }), 'value');
322	  };
323	
324	  // An internal function used for aggregate "group by" operations.
325	  var group = function(obj, value, context, behavior) {
326	    var result = {};
327	    var iterator = lookupIterator(value || _.identity);
328	    each(obj, function(value, index) {
329	      var key = iterator.call(context, value, index, obj);
330	      behavior(result, key, value);
331	    });
332	    return result;
333	  };
334	
335	  // Groups the object's values by a criterion. Pass either a string attribute
336	  // to group by, or a function that returns the criterion.
337	  _.groupBy = function(obj, value, context) {
338	    return group(obj, value, context, function(result, key, value) {
339	      (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
340	    });
341	  };
342	
343	  // Counts instances of an object that group by a certain criterion. Pass
344	  // either a string attribute to count by, or a function that returns the
345	  // criterion.
346	  _.countBy = function(obj, value, context) {
347	    return group(obj, value, context, function(result, key) {
348	      if (!_.has(result, key)) result[key] = 0;
349	      result[key]++;
350	    });
351	  };
352	
353	  // Use a comparator function to figure out the smallest index at which
354	  // an object should be inserted so as to maintain order. Uses binary search.
355	  _.sortedIndex = function(array, obj, iterator, context) {
356	    iterator = iterator == null ? _.identity : lookupIterator(iterator);
357	    var value = iterator.call(context, obj);
358	    var low = 0, high = array.length;
359	    while (low < high) {
360	      var mid = (low + high) >>> 1;
361	      iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
362	    }
363	    return low;
364	  };
365	
366	  // Safely convert anything iterable into a real, live array.
367	  _.toArray = function(obj) {
368	    if (!obj) return [];
369	    if (_.isArray(obj)) return slice.call(obj);
370	    if (obj.length === +obj.length) return _.map(obj, _.identity);
371	    return _.values(obj);
372	  };
373	
374	  // Return the number of elements in an object.
375	  _.size = function(obj) {
376	    if (obj == null) return 0;
377	    return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
378	  };
379	
380	  // Array Functions
381	  // ---------------
382	
383	  // Get the first element of an array. Passing **n** will return the first N
384	  // values in the array. Aliased as `head` and `take`. The **guard** check
385	  // allows it to work with `_.map`.
386	  _.first = _.head = _.take = function(array, n, guard) {
387	    if (array == null) return void 0;
388	    return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
389	  };
390	
391	  // Returns everything but the last entry of the array. Especially useful on
392	  // the arguments object. Passing **n** will return all the values in
393	  // the array, excluding the last N. The **guard** check allows it to work with
394	  // `_.map`.
395	  _.initial = function(array, n, guard) {
396	    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
397	  };
398	
399	  // Get the last element of an array. Passing **n** will return the last N
400	  // values in the array. The **guard** check allows it to work with `_.map`.
401	  _.last = function(array, n, guard) {
402	    if (array == null) return void 0;
403	    if ((n != null) && !guard) {
404	      return slice.call(array, Math.max(array.length - n, 0));
405	    } else {
406	      return array[array.length - 1];
407	    }
408	  };
409	
410	  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
411	  // Especially useful on the arguments object. Passing an **n** will return
412	  // the rest N values in the array. The **guard**
413	  // check allows it to work with `_.map`.
414	  _.rest = _.tail = _.drop = function(array, n, guard) {
415	    return slice.call(array, (n == null) || guard ? 1 : n);
416	  };
417	
418	  // Trim out all falsy values from an array.
419	  _.compact = function(array) {
420	    return _.filter(array, _.identity);
421	  };
422	
423	  // Internal implementation of a recursive `flatten` function.
424	  var flatten = function(input, shallow, output) {
425	    each(input, function(value) {
426	      if (_.isArray(value)) {
427	        shallow ? push.apply(output, value) : flatten(value, shallow, output);
428	      } else {
429	        output.push(value);
430	      }
431	    });
432	    return output;
433	  };
434	
435	  // Return a completely flattened version of an array.
436	  _.flatten = function(array, shallow) {
437	    return flatten(array, shallow, []);
438	  };
439	
440	  // Return a version of the array that does not contain the specified value(s).
441	  _.without = function(array) {
442	    return _.difference(array, slice.call(arguments, 1));
443	  };
444	
445	  // Produce a duplicate-free version of the array. If the array has already
446	  // been sorted, you have the option of using a faster algorithm.
447	  // Aliased as `unique`.
448	  _.uniq = _.unique = function(array, isSorted, iterator, context) {
449	    if (_.isFunction(isSorted)) {
450	      context = iterator;
451	      iterator = isSorted;
452	      isSorted = false;
453	    }
454	    var initial = iterator ? _.map(array, iterator, context) : array;
455	    var results = [];
456	    var seen = [];
457	    each(initial, function(value, index) {
458	      if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
459	        seen.push(value);
460	        results.push(array[index]);
461	      }
462	    });
463	    return results;
464	  };
465	
466	  // Produce an array that contains the union: each distinct element from all of
467	  // the passed-in arrays.
468	  _.union = function() {
469	    return _.uniq(concat.apply(ArrayProto, arguments));
470	  };
471	
472	  // Produce an array that contains every item shared between all the
473	  // passed-in arrays.
474	  _.intersection = function(array) {
475	    var rest = slice.call(arguments, 1);
476	    return _.filter(_.uniq(array), function(item) {
477	      return _.every(rest, function(other) {
478	        return _.indexOf(other, item) >= 0;
479	      });
480	    });
481	  };
482	
483	  // Take the difference between one array and a number of other arrays.
484	  // Only the elements present in just the first array will remain.
485	  _.difference = function(array) {
486	    var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
487	    return _.filter(array, function(value){ return !_.contains(rest, value); });
488	  };
489	
490	  // Zip together multiple lists into a single array -- elements that share
491	  // an index go together.
492	  _.zip = function() {
493	    var args = slice.call(arguments);
494	    var length = _.max(_.pluck(args, 'length'));
495	    var results = new Array(length);
496	    for (var i = 0; i < length; i++) {
497	      results[i] = _.pluck(args, "" + i);
498	    }
499	    return results;
500	  };
501	
502	  // Converts lists into objects. Pass either a single array of `[key, value]`
503	  // pairs, or two parallel arrays of the same length -- one of keys, and one of
504	  // the corresponding values.
505	  _.object = function(list, values) {
506	    if (list == null) return {};
507	    var result = {};
508	    for (var i = 0, l = list.length; i < l; i++) {
509	      if (values) {
510	        result[list[i]] = values[i];
511	      } else {
512	        result[list[i][0]] = list[i][1];
513	      }
514	    }
515	    return result;
516	  };
517	
518	  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
519	  // we need this function. Return the position of the first occurrence of an
520	  // item in an array, or -1 if the item is not included in the array.
521	  // Delegates to **ECMAScript 5**'s native `indexOf` if available.
522	  // If the array is large and already in sort order, pass `true`
523	  // for **isSorted** to use binary search.
524	  _.indexOf = function(array, item, isSorted) {
525	    if (array == null) return -1;
526	    var i = 0, l = array.length;
527	    if (isSorted) {
528	      if (typeof isSorted == 'number') {
529	        i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
530	      } else {
531	        i = _.sortedIndex(array, item);
532	        return array[i] === item ? i : -1;
533	      }
534	    }
535	    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
536	    for (; i < l; i++) if (array[i] === item) return i;
537	    return -1;
538	  };
539	
540	  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
541	  _.lastIndexOf = function(array, item, from) {
542	    if (array == null) return -1;
543	    var hasIndex = from != null;
544	    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
545	      return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
546	    }
547	    var i = (hasIndex ? from : array.length);
548	    while (i--) if (array[i] === item) return i;
549	    return -1;
550	  };
551	
552	  // Generate an integer Array containing an arithmetic progression. A port of
553	  // the native Python `range()` function. See
554	  // [the Python documentation](http://docs.python.org/library/functions.html#range).
555	  _.range = function(start, stop, step) {
556	    if (arguments.length <= 1) {
557	      stop = start || 0;
558	      start = 0;
559	    }
560	    step = arguments[2] || 1;
561	
562	    var len = Math.max(Math.ceil((stop - start) / step), 0);
563	    var idx = 0;
564	    var range = new Array(len);
565	
566	    while(idx < len) {
567	      range[idx++] = start;
568	      start += step;
569	    }
570	
571	    return range;
572	  };
573	
574	  // Function (ahem) Functions
575	  // ------------------
576	
577	  // Create a function bound to a given object (assigning `this`, and arguments,
578	  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
579	  // available.
580	  _.bind = function(func, context) {
581	    if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
582	    var args = slice.call(arguments, 2);
583	    return function() {
584	      return func.apply(context, args.concat(slice.call(arguments)));
585	    };
586	  };
587	
588	  // Partially apply a function by creating a version that has had some of its
589	  // arguments pre-filled, without changing its dynamic `this` context.
590	  _.partial = function(func) {
591	    var args = slice.call(arguments, 1);
592	    return function() {
593	      return func.apply(this, args.concat(slice.call(arguments)));
594	    };
595	  };
596	
597	  // Bind all of an object's methods to that object. Useful for ensuring that
598	  // all callbacks defined on an object belong to it.
599	  _.bindAll = function(obj) {
600	    var funcs = slice.call(arguments, 1);
601	    if (funcs.length === 0) funcs = _.functions(obj);
602	    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
603	    return obj;
604	  };
605	
606	  // Memoize an expensive function by storing its results.
607	  _.memoize = function(func, hasher) {
608	    var memo = {};
609	    hasher || (hasher = _.identity);
610	    return function() {
611	      var key = hasher.apply(this, arguments);
612	      return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
613	    };
614	  };
615	
616	  // Delays a function for the given number of milliseconds, and then calls
617	  // it with the arguments supplied.
618	  _.delay = function(func, wait) {
619	    var args = slice.call(arguments, 2);
620	    return setTimeout(function(){ return func.apply(null, args); }, wait);
621	  };
622	
623	  // Defers a function, scheduling it to run after the current call stack has
624	  // cleared.
625	  _.defer = function(func) {
626	    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
627	  };
628	
629	  // Returns a function, that, when invoked, will only be triggered at most once
630	  // during a given window of time.
631	  _.throttle = function(func, wait) {
632	    var context, args, timeout, result;
633	    var previous = 0;
634	    var later = function() {
635	      previous = new Date;
636	      timeout = null;
637	      result = func.apply(context, args);
638	    };
639	    return function() {
640	      var now = new Date;
641	      var remaining = wait - (now - previous);
642	      context = this;
643	      args = arguments;
644	      if (remaining <= 0) {
645	        clearTimeout(timeout);
646	        timeout = null;
647	        previous = now;
648	        result = func.apply(context, args);
649	      } else if (!timeout) {
650	        timeout = setTimeout(later, remaining);
651	      }
652	      return result;
653	    };
654	  };
655	
656	  // Returns a function, that, as long as it continues to be invoked, will not
657	  // be triggered. The function will be called after it stops being called for
658	  // N milliseconds. If `immediate` is passed, trigger the function on the
659	  // leading edge, instead of the trailing.
660	  _.debounce = function(func, wait, immediate) {
661	    var timeout, result;
662	    return function() {
663	      var context = this, args = arguments;
664	      var later = function() {
665	        timeout = null;
666	        if (!immediate) result = func.apply(context, args);
667	      };
668	      var callNow = immediate && !timeout;
669	      clearTimeout(timeout);
670	      timeout = setTimeout(later, wait);
671	      if (callNow) result = func.apply(context, args);
672	      return result;
673	    };
674	  };
675	
676	  // Returns a function that will be executed at most one time, no matter how
677	  // often you call it. Useful for lazy initialization.
678	  _.once = function(func) {
679	    var ran = false, memo;
680	    return function() {
681	      if (ran) return memo;
682	      ran = true;
683	      memo = func.apply(this, arguments);
684	      func = null;
685	      return memo;
686	    };
687	  };
688	
689	  // Returns the first function passed as an argument to the second,
690	  // allowing you to adjust arguments, run code before and after, and
691	  // conditionally execute the original function.
692	  _.wrap = function(func, wrapper) {
693	    return function() {
694	      var args = [func];
695	      push.apply(args, arguments);
696	      return wrapper.apply(this, args);
697	    };
698	  };
699	
700	  // Returns a function that is the composition of a list of functions, each
701	  // consuming the return value of the function that follows.
702	  _.compose = function() {
703	    var funcs = arguments;
704	    return function() {
705	      var args = arguments;
706	      for (var i = funcs.length - 1; i >= 0; i--) {
707	        args = [funcs[i].apply(this, args)];
708	      }
709	      return args[0];
710	    };
711	  };
712	
713	  // Returns a function that will only be executed after being called N times.
714	  _.after = function(times, func) {
715	    if (times <= 0) return func();
716	    return function() {
717	      if (--times < 1) {
718	        return func.apply(this, arguments);
719	      }
720	    };
721	  };
722	
723	  // Object Functions
724	  // ----------------
725	
726	  // Retrieve the names of an object's properties.
727	  // Delegates to **ECMAScript 5**'s native `Object.keys`
728	  _.keys = nativeKeys || function(obj) {
729	    if (obj !== Object(obj)) throw new TypeError('Invalid object');
730	    var keys = [];
731	    for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
732	    return keys;
733	  };
734	
735	  // Retrieve the values of an object's properties.
736	  _.values = function(obj) {
737	    var values = [];
738	    for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
739	    return values;
740	  };
741	
742	  // Convert an object into a list of `[key, value]` pairs.
743	  _.pairs = function(obj) {
744	    var pairs = [];
745	    for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
746	    return pairs;
747	  };
748	
749	  // Invert the keys and values of an object. The values must be serializable.
750	  _.invert = function(obj) {
751	    var result = {};
752	    for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
753	    return result;
754	  };
755	
756	  // Return a sorted list of the function names available on the object.
757	  // Aliased as `methods`
758	  _.functions = _.methods = function(obj) {
759	    var names = [];
760	    for (var key in obj) {
761	      if (_.isFunction(obj[key])) names.push(key);
762	    }
763	    return names.sort();
764	  };
765	
766	  // Extend a given object with all the properties in passed-in object(s).
767	  _.extend = function(obj) {
768	    each(slice.call(arguments, 1), function(source) {
769	      if (source) {
770	        for (var prop in source) {
771	          obj[prop] = source[prop];
772	        }
773	      }
774	    });
775	    return obj;
776	  };
777	
778	  // Return a copy of the object only containing the whitelisted properties.
779	  _.pick = function(obj) {
780	    var copy = {};
781	    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
782	    each(keys, function(key) {
783	      if (key in obj) copy[key] = obj[key];
784	    });
785	    return copy;
786	  };
787	
788	   // Return a copy of the object without the blacklisted properties.
789	  _.omit = function(obj) {
790	    var copy = {};
791	    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
792	    for (var key in obj) {
793	      if (!_.contains(keys, key)) copy[key] = obj[key];
794	    }
795	    return copy;
796	  };
797	
798	  // Fill in a given object with default properties.
799	  _.defaults = function(obj) {
800	    each(slice.call(arguments, 1), function(source) {
801	      if (source) {
802	        for (var prop in source) {
803	          if (obj[prop] == null) obj[prop] = source[prop];
804	        }
805	      }
806	    });
807	    return obj;
808	  };
809	
810	  // Create a (shallow-cloned) duplicate of an object.
811	  _.clone = function(obj) {
812	    if (!_.isObject(obj)) return obj;
813	    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
814	  };
815	
816	  // Invokes interceptor with the obj, and then returns obj.
817	  // The primary purpose of this method is to "tap into" a method chain, in
818	  // order to perform operations on intermediate results within the chain.
819	  _.tap = function(obj, interceptor) {
820	    interceptor(obj);
821	    return obj;
822	  };
823	
824	  // Internal recursive comparison function for `isEqual`.
825	  var eq = function(a, b, aStack, bStack) {
826	    // Identical objects are equal. `0 === -0`, but they aren't identical.
827	    // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
828	    if (a === b) return a !== 0 || 1 / a == 1 / b;
829	    // A strict comparison is necessary because `null == undefined`.
830	    if (a == null || b == null) return a === b;
831	    // Unwrap any wrapped objects.
832	    if (a instanceof _) a = a._wrapped;
833	    if (b instanceof _) b = b._wrapped;
834	    // Compare `[[Class]]` names.
835	    var className = toString.call(a);
836	    if (className != toString.call(b)) return false;
837	    switch (className) {
838	      // Strings, numbers, dates, and booleans are compared by value.
839	      case '[object String]':
840	        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
841	        // equivalent to `new String("5")`.
842	        return a == String(b);
843	      case '[object Number]':
844	        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
845	        // other numeric values.
846	        return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
847	      case '[object Date]':
848	      case '[object Boolean]':
849	        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
850	        // millisecond representations. Note that invalid dates with millisecond representations
851	        // of `NaN` are not equivalent.
852	        return +a == +b;
853	      // RegExps are compared by their source patterns and flags.
854	      case '[object RegExp]':
855	        return a.source == b.source &&
856	               a.global == b.global &&
857	               a.multiline == b.multiline &&
858	               a.ignoreCase == b.ignoreCase;
859	    }
860	    if (typeof a != 'object' || typeof b != 'object') return false;
861	    // Assume equality for cyclic structures. The algorithm for detecting cyclic
862	    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
863	    var length = aStack.length;
864	    while (length--) {
865	      // Linear search. Performance is inversely proportional to the number of
866	      // unique nested structures.
867	      if (aStack[length] == a) return bStack[length] == b;
868	    }
869	    // Add the first object to the stack of traversed objects.
870	    aStack.push(a);
871	    bStack.push(b);
872	    var size = 0, result = true;
873	    // Recursively compare objects and arrays.
874	    if (className == '[object Array]') {
875	      // Compare array lengths to determine if a deep comparison is necessary.
876	      size = a.length;
877	      result = size == b.length;
878	      if (result) {
879	        // Deep compare the contents, ignoring non-numeric properties.
880	        while (size--) {
881	          if (!(result = eq(a[size], b[size], aStack, bStack))) break;
882	        }
883	      }
884	    } else {
885	      // Objects with different constructors are not equivalent, but `Object`s
886	      // from different frames are.
887	      var aCtor = a.constructor, bCtor = b.constructor;
888	      if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
889	                               _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
890	        return false;
891	      }
892	      // Deep compare objects.
893	      for (var key in a) {
894	        if (_.has(a, key)) {
895	          // Count the expected number of properties.
896	          size++;
897	          // Deep compare each member.
898	          if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
899	        }
900	      }
901	      // Ensure that both objects contain the same number of properties.
902	      if (result) {
903	        for (key in b) {
904	          if (_.has(b, key) && !(size--)) break;
905	        }
906	        result = !size;
907	      }
908	    }
909	    // Remove the first object from the stack of traversed objects.
910	    aStack.pop();
911	    bStack.pop();
912	    return result;
913	  };
914	
915	  // Perform a deep comparison to check if two objects are equal.
916	  _.isEqual = function(a, b) {
917	    return eq(a, b, [], []);
918	  };
919	
920	  // Is a given array, string, or object empty?
921	  // An "empty" object has no enumerable own-properties.
922	  _.isEmpty = function(obj) {
923	    if (obj == null) return true;
924	    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
925	    for (var key in obj) if (_.has(obj, key)) return false;
926	    return true;
927	  };
928	
929	  // Is a given value a DOM element?
930	  _.isElement = function(obj) {
931	    return !!(obj && obj.nodeType === 1);
932	  };
933	
934	  // Is a given value an array?
935	  // Delegates to ECMA5's native Array.isArray
936	  _.isArray = nativeIsArray || function(obj) {
937	    return toString.call(obj) == '[object Array]';
938	  };
939	
940	  // Is a given variable an object?
941	  _.isObject = function(obj) {
942	    return obj === Object(obj);
943	  };
944	
945	  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
946	  each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
947	    _['is' + name] = function(obj) {
948	      return toString.call(obj) == '[object ' + name + ']';
949	    };
950	  });
951	
952	  // Define a fallback version of the method in browsers (ahem, IE), where
953	  // there isn't any inspectable "Arguments" type.
954	  if (!_.isArguments(arguments)) {
955	    _.isArguments = function(obj) {
956	      return !!(obj && _.has(obj, 'callee'));
957	    };
958	  }
959	
960	  // Optimize `isFunction` if appropriate.
961	  if (typeof (/./) !== 'function') {
962	    _.isFunction = function(obj) {
963	      return typeof obj === 'function';
964	    };
965	  }
966	
967	  // Is a given object a finite number?
968	  _.isFinite = function(obj) {
969	    return isFinite(obj) && !isNaN(parseFloat(obj));
970	  };
971	
972	  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
973	  _.isNaN = function(obj) {
974	    return _.isNumber(obj) && obj != +obj;
975	  };
976	
977	  // Is a given value a boolean?
978	  _.isBoolean = function(obj) {
979	    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
980	  };
981	
982	  // Is a given value equal to null?
983	  _.isNull = function(obj) {
984	    return obj === null;
985	  };
986	
987	  // Is a given variable undefined?
988	  _.isUndefined = function(obj) {
989	    return obj === void 0;
990	  };
991	
992	  // Shortcut function for checking if an object has a given property directly
993	  // on itself (in other words, not on a prototype).
994	  _.has = function(obj, key) {
995	    return hasOwnProperty.call(obj, key);
996	  };
997	
998	  // Utility Functions
999	  // -----------------
1000	
1001	  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
1002	  // previous owner. Returns a reference to the Underscore object.
1003	  _.noConflict = function() {
1004	    root._ = previousUnderscore;
1005	    return this;
1006	  };
1007	
1008	  // Keep the identity function around for default iterators.
1009	  _.identity = function(value) {
1010	    return value;
1011	  };
1012	
1013	  // Run a function **n** times.
1014	  _.times = function(n, iterator, context) {
1015	    var accum = Array(n);
1016	    for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
1017	    return accum;
1018	  };
1019	
1020	  // Return a random integer between min and max (inclusive).
1021	  _.random = function(min, max) {
1022	    if (max == null) {
1023	      max = min;
1024	      min = 0;
1025	    }
1026	    return min + Math.floor(Math.random() * (max - min + 1));
1027	  };
1028	
1029	  // List of HTML entities for escaping.
1030	  var entityMap = {
1031	    escape: {
1032	      '&': '&amp;',
1033	      '<': '&lt;',
1034	      '>': '&gt;',
1035	      '"': '&quot;',
1036	      "'": '&#x27;',
1037	      '/': '&#x2F;'
1038	    }
1039	  };
1040	  entityMap.unescape = _.invert(entityMap.escape);
1041	
1042	  // Regexes containing the keys and values listed immediately above.
1043	  var entityRegexes = {
1044	    escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
1045	    unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
1046	  };
1047	
1048	  // Functions for escaping and unescaping strings to/from HTML interpolation.
1049	  _.each(['escape', 'unescape'], function(method) {
1050	    _[method] = function(string) {
1051	      if (string == null) return '';
1052	      return ('' + string).replace(entityRegexes[method], function(match) {
1053	        return entityMap[method][match];
1054	      });
1055	    };
1056	  });
1057	
1058	  // If the value of the named property is a function then invoke it;
1059	  // otherwise, return it.
1060	  _.result = function(object, property) {
1061	    if (object == null) return null;
1062	    var value = object[property];
1063	    return _.isFunction(value) ? value.call(object) : value;
1064	  };
1065	
1066	  // Add your own custom functions to the Underscore object.
1067	  _.mixin = function(obj) {
1068	    each(_.functions(obj), function(name){
1069	      var func = _[name] = obj[name];
1070	      _.prototype[name] = function() {
1071	        var args = [this._wrapped];
1072	        push.apply(args, arguments);
1073	        return result.call(this, func.apply(_, args));
1074	      };
1075	    });
1076	  };
1077	
1078	  // Generate a unique integer id (unique within the entire client session).
1079	  // Useful for temporary DOM ids.
1080	  var idCounter = 0;
1081	  _.uniqueId = function(prefix) {
1082	    var id = ++idCounter + '';
1083	    return prefix ? prefix + id : id;
1084	  };
1085	
1086	  // By default, Underscore uses ERB-style template delimiters, change the
1087	  // following template settings to use alternative delimiters.
1088	  _.templateSettings = {
1089	    evaluate    : /<%([\s\S]+?)%>/g,
1090	    interpolate : /<%=([\s\S]+?)%>/g,
1091	    escape      : /<%-([\s\S]+?)%>/g
1092	  };
1093	
1094	  // When customizing `templateSettings`, if you don't want to define an
1095	  // interpolation, evaluation or escaping regex, we need one that is
1096	  // guaranteed not to match.
1097	  var noMatch = /(.)^/;
1098	
1099	  // Certain characters need to be escaped so that they can be put into a
1100	  // string literal.
1101	  var escapes = {
1102	    "'":      "'",
1103	    '\\':     '\\',
1104	    '\r':     'r',
1105	    '\n':     'n',
1106	    '\t':     't',
1107	    '\u2028': 'u2028',
1108	    '\u2029': 'u2029'
1109	  };
1110	
1111	  var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
1112	
1113	  // JavaScript micro-templating, similar to John Resig's implementation.
1114	  // Underscore templating handles arbitrary delimiters, preserves whitespace,
1115	  // and correctly escapes quotes within interpolated code.
1116	  _.template = function(text, data, settings) {
1117	    var render;
1118	    settings = _.defaults({}, settings, _.templateSettings);
1119	
1120	    // Combine delimiters into one regular expression via alternation.
1121	    var matcher = new RegExp([
1122	      (settings.escape || noMatch).source,
1123	      (settings.interpolate || noMatch).source,
1124	      (settings.evaluate || noMatch).source
1125	    ].join('|') + '|$', 'g');
1126	
1127	    // Compile the template source, escaping string literals appropriately.
1128	    var index = 0;
1129	    var source = "__p+='";
1130	    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
1131	      source += text.slice(index, offset)
1132	        .replace(escaper, function(match) { return '\\' + escapes[match]; });
1133	
1134	      if (escape) {
1135	        source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
1136	      }
1137	      if (interpolate) {
1138	        source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
1139	      }
1140	      if (evaluate) {
1141	        source += "';\n" + evaluate + "\n__p+='";
1142	      }
1143	      index = offset + match.length;
1144	      return match;
1145	    });
1146	    source += "';\n";
1147	
1148	    // If a variable is not specified, place data values in local scope.
1149	    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
1150	
1151	    source = "var __t,__p='',__j=Array.prototype.join," +
1152	      "print=function(){__p+=__j.call(arguments,'');};\n" +
1153	      source + "return __p;\n";
1154	
1155	    try {
1156	      render = new Function(settings.variable || 'obj', '_', source);
1157	    } catch (e) {
1158	      e.source = source;
1159	      throw e;
1160	    }
1161	
1162	    if (data) return render(data, _);
1163	    var template = function(data) {
1164	      return render.call(this, data, _);
1165	    };
1166	
1167	    // Provide the compiled function source as a convenience for precompilation.
1168	    template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
1169	
1170	    return template;
1171	  };
1172	
1173	  // Add a "chain" function, which will delegate to the wrapper.
1174	  _.chain = function(obj) {
1175	    return _(obj).chain();
1176	  };
1177	
1178	  // OOP
1179	  // ---------------
1180	  // If Underscore is called as a function, it returns a wrapped object that
1181	  // can be used OO-style. This wrapper holds altered versions of all the
1182	  // underscore functions. Wrapped objects may be chained.
1183	
1184	  // Helper function to continue chaining intermediate results.
1185	  var result = function(obj) {
1186	    return this._chain ? _(obj).chain() : obj;
1187	  };
1188	
1189	  // Add all of the Underscore functions to the wrapper object.
1190	  _.mixin(_);
1191	
1192	  // Add all mutator Array functions to the wrapper.
1193	  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
1194	    var method = ArrayProto[name];
1195	    _.prototype[name] = function() {
1196	      var obj = this._wrapped;
1197	      method.apply(obj, arguments);
1198	      if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
1199	      return result.call(this, obj);
1200	    };
1201	  });
1202	
1203	  // Add all accessor Array functions to the wrapper.
1204	  each(['concat', 'join', 'slice'], function(name) {
1205	    var method = ArrayProto[name];
1206	    _.prototype[name] = function() {
1207	      return result.call(this, method.apply(this._wrapped, arguments));
1208	    };
1209	  });
1210	
1211	  _.extend(_.prototype, {
1212	
1213	    // Start chaining a wrapped Underscore object.
1214	    chain: function() {
1215	      this._chain = true;
1216	      return this;
1217	    },
1218	
1219	    // Extracts the result from a wrapped and chained object.
1220	    value: function() {
1221	      return this._wrapped;
1222	    }
1223	
1224	  });
1225	
1226	}).call(this);

Contacte con nosotros
¿No puede leer el artículo? ¡Póngase en contacto con nosotros para obtener una respuesta gratuita! Ayuda gratuita para sitios personales y de pequeñas empresas
Tel: 020-2206-9892
QQ咨询:1025174874
(iii) Correo electrónico: info@361sale.com
Horario de trabajo: de lunes a viernes, de 9:30 a 18:30, días festivos libres
© Declaración de reproducción
Este artículo fue escrito por Harry
EL FIN
Si le gusta, apóyela.
felicitaciones0 compartir (alegrías, beneficios, privilegios, etc.) con los demás
comentarios compra de sofás

Por favor, inicie sesión para enviar un comentario

    Sin comentarios