From c714175cf17f59a60b848a1f3bdaa1e3076fc1c1 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Wed, 1 Dec 2010 12:49:45 -0500 Subject: [PATCH] Underscore.js 1.1.3 --- docs/docco.css | 8 +- docs/underscore.html | 247 ++++++++++++++++++++++++------------------- index.html | 74 ++++++++----- package.json | 2 +- underscore-min.js | 31 +++--- underscore.js | 4 +- 6 files changed, 211 insertions(+), 155 deletions(-) diff --git a/docs/docco.css b/docs/docco.css index b2e601974..5aa0a8d73 100644 --- a/docs/docco.css +++ b/docs/docco.css @@ -16,17 +16,17 @@ p { margin: 0 0 15px 0; } h1, h2, h3, h4, h5, h6 { - margin: 40px 0 15px 0; + margin: 0px 0 15px 0; } - h3, h4, h5, h6 { - margin-top: 20px; + h1 { + margin-top: 40px; } #container { position: relative; } #background { position: fixed; - top: 0; left: 575px; right: 0; bottom: 0; + top: 0; left: 525px; right: 0; bottom: 0; background: #f5f5ff; border-left: 1px solid #e5e5ee; z-index: -1; diff --git a/docs/underscore.html b/docs/underscore.html index 76af64f34..44bed11a2 100644 --- a/docs/underscore.html +++ b/docs/underscore.html @@ -1,14 +1,14 @@ - underscore.js

underscore.js

(c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
+      underscore.js           
iterator(array[mid])<iterator(obj)?low=mid+1:high=mid;}returnlow; - };}returnargs[0];}; - };+"');}return __p.join('');";varfunc=newFunction('obj',tmpl);returndata?func(data):func; - };

underscore.js

Underscore.js 1.1.3
+(c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
 Underscore is freely distributable under the MIT license.
 Portions of Underscore are inspired or borrowed from Prototype,
 Oliver Steele's Functional, and John Resig's Micro-Templating.
 For all details and documentation:
 http://documentcloud.github.com/underscore
-
(function() {

Baseline setup

Establish the root object, window in the browser, or global on the server.

  var root = this;

Save the previous value of the _ variable.

  var previousUnderscore = root._;

Establish the object that gets thrown to break out of a loop iteration.

  var breaker = typeof StopIteration !== 'undefined' ? StopIteration : '__break__';

Save bytes in the minified (but not gzipped) version:

  var ArrayProto = Array.prototype, ObjProto = Object.prototype;

Create quick reference variables for speed access to core prototypes.

  var slice                 = ArrayProto.slice,
-      unshift               = ArrayProto.unshift,
-      toString              = ObjProto.toString,
-      hasOwnProperty        = ObjProto.hasOwnProperty,
-      propertyIsEnumerable  = ObjProto.propertyIsEnumerable;

All ECMAScript 5 native function implementations that we hope to use +

(function() {

Baseline setup

Establish the root object, window in the browser, or global on the server.

  var root = this;

Save the previous value of the _ variable.

  var previousUnderscore = root._;

Establish the object that gets returned to break out of a loop iteration.

  var breaker = {};

Save bytes in the minified (but not gzipped) version:

  var ArrayProto = Array.prototype, ObjProto = Object.prototype;

Create quick reference variables for speed access to core prototypes.

  var slice            = ArrayProto.slice,
+      unshift          = ArrayProto.unshift,
+      toString         = ObjProto.toString,
+      hasOwnProperty   = ObjProto.hasOwnProperty;

All ECMAScript 5 native function implementations that we hope to use are declared here.

  var
     nativeForEach      = ArrayProto.forEach,
     nativeMap          = ArrayProto.map,
@@ -20,24 +20,31 @@ are declared here.

nativeIndexOf = ArrayProto.indexOf, nativeLastIndexOf = ArrayProto.lastIndexOf, nativeIsArray = Array.isArray, - nativeKeys = Object.keys;

Create a safe reference to the Underscore object for use below.

  var _ = function(obj) { return new wrapper(obj); };

Export the Underscore object for CommonJS.

  if (typeof exports !== 'undefined') exports._ = _;

Export Underscore to the global scope.

  root._ = _;

Current version.

  _.VERSION = '1.1.2';

Collection Functions

The cornerstone, an each implementation, aka forEach. + nativeKeys = Object.keys;

Create a safe reference to the Underscore object for use below.

  var _ = function(obj) { return new wrapper(obj); };

Export the Underscore object for CommonJS, with backwards-compatibility +for the old require() API. If we're not in CommonJS, add _ to the +global object.

  if (typeof module !== 'undefined' && module.exports) {
+    module.exports = _;
+    _._ = _;
+  } else {
+    root._ = _;
+  }

Current version.

  _.VERSION = '1.1.3';

Collection Functions

The cornerstone, an each implementation, aka forEach. Handles objects implementing forEach, arrays, and raw objects. Delegates to ECMAScript 5's native forEach if available.

  var each = _.each = _.forEach = function(obj, iterator, context) {
-    try {
-      if (nativeForEach && obj.forEach === nativeForEach) {
-        obj.forEach(iterator, context);
-      } else if (_.isNumber(obj.length)) {
-        for (var i = 0, l = obj.length; i < l; i++) iterator.call(context, obj[i], i, obj);
-      } else {
-        for (var key in obj) {
-          if (hasOwnProperty.call(obj, key)) iterator.call(context, obj[key], key, obj);
+    var value;
+    if (nativeForEach && obj.forEach === nativeForEach) {
+      obj.forEach(iterator, context);
+    } else if (_.isNumber(obj.length)) {
+      for (var i = 0, l = obj.length; i < l; i++) {
+        if (iterator.call(context, obj[i], i, obj) === breaker) return;
+      }
+    } else {
+      for (var key in obj) {
+        if (hasOwnProperty.call(obj, key)) {
+          if (iterator.call(context, obj[key], key, obj) === breaker) return;
         }
       }
-    } catch(e) {
-      if (e != breaker) throw e;
     }
-    return obj;
-  };

Return the results of applying the iterator to each element. + };

Return the results of applying the iterator to each element. Delegates to ECMAScript 5's native map if available.

  _.map = function(obj, iterator, context) {
     if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
     var results = [];
@@ -45,34 +52,39 @@ Delegates to ECMAScript 5's native map if availabl
       results[results.length] = iterator.call(context, value, index, list);
     });
     return results;
-  };

Reduce builds up a single result from a list of values, aka inject, + };

Reduce builds up a single result from a list of values, aka inject, or foldl. Delegates to ECMAScript 5's native reduce if available.

  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
+    var initial = memo !== void 0;
     if (nativeReduce && obj.reduce === nativeReduce) {
       if (context) iterator = _.bind(iterator, context);
-      return obj.reduce(iterator, memo);
+      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
     }
     each(obj, function(value, index, list) {
-      memo = iterator.call(context, memo, value, index, list);
+      if (!initial && index === 0) {
+        memo = value;
+      } else {
+        memo = iterator.call(context, memo, value, index, list);
+      }
     });
     return memo;
-  };

The right-associative version of reduce, also known as foldr. + };

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) {
     if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
       if (context) iterator = _.bind(iterator, context);
-      return obj.reduceRight(iterator, memo);
+      return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
     }
     var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse();
     return _.reduce(reversed, iterator, memo, context);
-  };

Return the first value which passes a truth test. Aliased as detect.

  _.find = _.detect = function(obj, iterator, context) {
+  };

Return the first value which passes a truth test. Aliased as detect.

  _.find = _.detect = function(obj, iterator, context) {
     var result;
-    each(obj, function(value, index, list) {
+    any(obj, function(value, index, list) {
       if (iterator.call(context, value, index, list)) {
         result = value;
-        _.breakLoop();
+        return true;
       }
     });
     return result;
-  };

Return all the elements that pass a truth test. + };

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, iterator, context) {
     if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
@@ -81,48 +93,48 @@ Aliased as select.

if (iterator.call(context, value, index, list)) results[results.length] = value; }); return results; - };

Return all the elements for which a truth test fails.

  _.reject = function(obj, iterator, context) {
+  };

Return all the elements for which a truth test fails.

  _.reject = function(obj, iterator, context) {
     var results = [];
     each(obj, function(value, index, list) {
       if (!iterator.call(context, value, index, list)) results[results.length] = value;
     });
     return results;
-  };

Determine whether all of the elements match a truth test. + };

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, iterator, context) {
     iterator = iterator || _.identity;
     if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
     var result = true;
     each(obj, function(value, index, list) {
-      if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop();
+      if (!(result = result && iterator.call(context, value, index, list))) return breaker;
     });
     return result;
-  };

Determine if at least one element in the object matches a truth test. + };

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.

  _.some = _.any = function(obj, iterator, context) {
+Aliased as any.

  var any = _.some = _.any = function(obj, iterator, context) {
     iterator = iterator || _.identity;
     if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
     var result = false;
     each(obj, function(value, index, list) {
-      if (result = iterator.call(context, value, index, list)) _.breakLoop();
+      if (result = iterator.call(context, value, index, list)) return breaker;
     });
     return result;
-  };

Determine if a given value is included in the array or object using ===. + };

Determine if a given value is included in the array or object using ===. Aliased as contains.

  _.include = _.contains = function(obj, target) {
     if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
     var found = false;
-    each(obj, function(value) {
-      if (found = value === target) _.breakLoop();
+    any(obj, function(value) {
+      if (found = value === target) return true;
     });
     return found;
-  };

Invoke a method (with arguments) on every item in a collection.

  _.invoke = function(obj, method) {
+  };

Invoke a method (with arguments) on every item in a collection.

  _.invoke = function(obj, method) {
     var args = slice.call(arguments, 2);
     return _.map(obj, function(value) {
       return (method ? value[method] : value).apply(value, args);
     });
-  };

Convenience version of a common use case of map: fetching a property.

  _.pluck = function(obj, key) {
+  };

Convenience version of a common use case of map: fetching a property.

  _.pluck = function(obj, key) {
     return _.map(obj, function(value){ return value[key]; });
-  };

Return the maximum element or (element-based computation).

  _.max = function(obj, iterator, context) {
+  };

Return the maximum element or (element-based computation).

  _.max = function(obj, iterator, context) {
     if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
     var result = {computed : -Infinity};
     each(obj, function(value, index, list) {
@@ -130,7 +142,7 @@ Aliased as contains.

computed >= result.computed && (result = {value : value, computed : computed}); }); return result.value; - };

Return the minimum element (or element-based computation).

  _.min = function(obj, iterator, context) {
+  };

Return the minimum element (or element-based computation).

  _.min = function(obj, iterator, context) {
     if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
     var result = {computed : Infinity};
     each(obj, function(value, index, list) {
@@ -138,7 +150,7 @@ Aliased as contains.

computed < result.computed && (result = {value : value, computed : computed}); }); return result.value; - };

Sort the object's values by a criterion produced by an iterator.

  _.sortBy = function(obj, iterator, context) {
+  };

Sort the object's values by a criterion produced by an iterator.

  _.sortBy = function(obj, iterator, context) {
     return _.pluck(_.map(obj, function(value, index, list) {
       return {
         value : value,
@@ -148,7 +160,7 @@ Aliased as contains.

var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; }), 'value'); - };

Use a comparator function to figure out at what index an object should + };

Use a comparator function to figure out at what index an object should be inserted so as to maintain order. Uses binary search.

  _.sortedIndex = function(array, obj, iterator) {
     iterator = iterator || _.identity;
     var low = 0, high = array.length;
@@ -157,44 +169,44 @@ be inserted so as to maintain order. Uses binary search.

Safely convert anything iterable into a real, live array.

  _.toArray = function(iterable) {
+  };

Safely convert anything iterable into a real, live array.

  _.toArray = function(iterable) {
     if (!iterable)                return [];
     if (iterable.toArray)         return iterable.toArray();
     if (_.isArray(iterable))      return iterable;
     if (_.isArguments(iterable))  return slice.call(iterable);
     return _.values(iterable);
-  };

Return the number of elements in an object.

  _.size = function(obj) {
+  };

Return the number of elements in an object.

  _.size = function(obj) {
     return _.toArray(obj).length;
-  };

Array Functions

Get the first element of an array. Passing n will return the first N + };

Array Functions

Get the first element of an array. Passing n will return the first N values in the array. Aliased as head. The guard check allows it to work with _.map.

  _.first = _.head = function(array, n, guard) {
     return n && !guard ? slice.call(array, 0, n) : array[0];
-  };

Returns everything but the first entry of the array. Aliased as tail. + };

Returns everything but the first entry of the array. Aliased as tail. Especially useful on the arguments object. Passing an index will return the rest of the values in the array from that index onward. The guard check allows it to work with _.map.

  _.rest = _.tail = function(array, index, guard) {
     return slice.call(array, _.isUndefined(index) || guard ? 1 : index);
-  };

Get the last element of an array.

  _.last = function(array) {
+  };

Get the last element of an array.

  _.last = function(array) {
     return array[array.length - 1];
-  };

Trim out all falsy values from an array.

  _.compact = function(array) {
+  };

Trim out all falsy values from an array.

  _.compact = function(array) {
     return _.filter(array, function(value){ return !!value; });
-  };

Return a completely flattened version of an array.

  _.flatten = function(array) {
+  };

Return a completely flattened version of an array.

  _.flatten = function(array) {
     return _.reduce(array, function(memo, value) {
       if (_.isArray(value)) return memo.concat(_.flatten(value));
       memo[memo.length] = value;
       return memo;
     }, []);
-  };

Return a version of the array that does not contain the specified value(s).

  _.without = function(array) {
+  };

Return a version of the array that does not contain the specified value(s).

  _.without = function(array) {
     var values = slice.call(arguments, 1);
     return _.filter(array, function(value){ return !_.include(values, value); });
-  };

Produce a duplicate-free version of the array. If the array has already + };

Produce a duplicate-free version of the array. If the array has already been sorted, you have the option of using a faster algorithm. Aliased as unique.

  _.uniq = _.unique = function(array, isSorted) {
     return _.reduce(array, function(memo, el, i) {
       if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;
       return memo;
     }, []);
-  };

Produce an array that contains every item shared between all the + };

Produce an array that contains every item shared between all the passed-in arrays.

  _.intersect = function(array) {
     var rest = slice.call(arguments, 1);
     return _.filter(_.uniq(array), function(item) {
@@ -202,26 +214,26 @@ passed-in arrays.

return _.indexOf(other, item) >= 0; }); }); - };

Zip together multiple lists into a single array -- elements that share + };

Zip together multiple lists into a single array -- elements that share an index go together.

  _.zip = function() {
     var args = slice.call(arguments);
     var length = _.max(_.pluck(args, 'length'));
     var results = new Array(length);
     for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
     return results;
-  };

If the browser doesn't supply us with indexOf (I'm looking at you, MSIE), + };

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.

  _.indexOf = function(array, item) {
     if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
     for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
     return -1;
-  };

Delegates to ECMAScript 5's native lastIndexOf if available.

  _.lastIndexOf = function(array, item) {
+  };

Delegates to ECMAScript 5's native lastIndexOf if available.

  _.lastIndexOf = function(array, item) {
     if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
     var i = array.length;
     while (i--) if (array[i] === item) return i;
     return -1;
-  };

Generate an integer Array containing an arithmetic progression. A port of + };

Generate an integer Array containing an arithmetic progression. A port of the native Python range() function. See the Python documentation.

  _.range = function(start, stop, step) {
     var args  = slice.call(arguments),
@@ -237,40 +249,58 @@ the native Python range() function. See
       start += step;
     }
     return range;
-  };

Function (ahem) Functions

Create a function bound to a given object (assigning this, and arguments, + };

Function (ahem) Functions

Create a function bound to a given object (assigning this, and arguments, optionally). Binding with arguments is also known as curry.

  _.bind = function(func, obj) {
     var args = slice.call(arguments, 2);
     return function() {
       return func.apply(obj || {}, args.concat(slice.call(arguments)));
     };
-  };

Bind all of an object's methods to that object. Useful for ensuring that + };

Bind all of an object's methods to that object. Useful for ensuring that all callbacks defined on an object belong to it.

  _.bindAll = function(obj) {
     var funcs = slice.call(arguments, 1);
     if (funcs.length == 0) funcs = _.functions(obj);
     each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
     return obj;
-  };

Memoize an expensive function by storing its results.

  _.memoize = function(func, hasher) {
+  };

Memoize an expensive function by storing its results.

  _.memoize = function(func, hasher) {
     var memo = {};
     hasher = hasher || _.identity;
     return function() {
       var key = hasher.apply(this, arguments);
       return key in memo ? memo[key] : (memo[key] = func.apply(this, arguments));
     };
-  };

Delays a function for the given number of milliseconds, and then calls + };

Delays a function for the given number of milliseconds, and then calls it with the arguments supplied.

  _.delay = function(func, wait) {
     var args = slice.call(arguments, 2);
     return setTimeout(function(){ return func.apply(func, args); }, wait);
-  };

Defers a function, scheduling it to run after the current call stack has + };

Defers a function, scheduling it to run after the current call stack has cleared.

  _.defer = function(func) {
     return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
-  };

Returns the first function passed as an argument to the second, + };

Internal function used to implement _.throttle and _.debounce.

  var limit = function(func, wait, debounce) {
+    var timeout;
+    return function() {
+      var context = this, args = arguments;
+      var throttler = function() {
+        timeout = null;
+        func.apply(context, args);
+      };
+      if (debounce) clearTimeout(timeout);
+      if (debounce || !timeout) timeout = setTimeout(throttler, wait);
+    };
+  };

Returns a function, that, when invoked, will only be triggered at most once +during a given window of time.

  _.throttle = function(func, wait) {
+    return limit(func, wait, false);
+  };

Returns a function, that, as long as it continues to be invoked, will not +be triggered. The function will be called after it stops being called for +N milliseconds.

  _.debounce = function(func, wait) {
+    return limit(func, wait, true);
+  };

Returns the first function passed as an argument to the second, allowing you to adjust arguments, run code before and after, and conditionally execute the original function.

  _.wrap = function(func, wrapper) {
     return function() {
       var args = [func].concat(slice.call(arguments));
       return wrapper.apply(wrapper, args);
     };
-  };

Returns a function that is the composition of a list of functions, each + };

Returns a function that is the composition of a list of functions, each consuming the return value of the function that follows.

  _.compose = function() {
     var funcs = slice.call(arguments);
     return function() {
@@ -280,97 +310,96 @@ consuming the return value of the function that follows.

Object Functions

Retrieve the names of an object's properties. + };

Object Functions

Retrieve the names of an object's properties. Delegates to ECMAScript 5's native Object.keys

  _.keys = nativeKeys || function(obj) {
     if (_.isArray(obj)) return _.range(0, obj.length);
     var keys = [];
     for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
     return keys;
-  };

Retrieve the values of an object's properties.

  _.values = function(obj) {
+  };

Retrieve the values of an object's properties.

  _.values = function(obj) {
     return _.map(obj, _.identity);
-  };

Return a sorted list of the function names available on the object. + };

Return a sorted list of the function names available on the object. Aliased as methods

  _.functions = _.methods = function(obj) {
     return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
-  };

Extend a given object with all the properties in passed-in object(s).

  _.extend = function(obj) {
+  };

Extend a given object with all the properties in passed-in object(s).

  _.extend = function(obj) {
     each(slice.call(arguments, 1), function(source) {
       for (var prop in source) obj[prop] = source[prop];
     });
     return obj;
-  };

Create a (shallow-cloned) duplicate of an object.

  _.clone = function(obj) {
+  };

Create a (shallow-cloned) duplicate of an object.

  _.clone = function(obj) {
     return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
-  };

Invokes interceptor with the obj, and then returns obj. + };

Invokes interceptor with the obj, and then returns obj. The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain.

  _.tap = function(obj, interceptor) {
     interceptor(obj);
     return obj;
-  };

Perform a deep comparison to check if two objects are equal.

  _.isEqual = function(a, b) {

Check object identity.

    if (a === b) return true;

Different types?

    var atype = typeof(a), btype = typeof(b);
-    if (atype != btype) return false;

Basic equality test (watch out for coercions).

    if (a == b) return true;

One is falsy and the other truthy.

    if ((!a && b) || (a && !b)) return false;

One of them implements an isEqual()?

    if (a.isEqual) return a.isEqual(b);

Check dates' integer values.

    if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();

Both are NaN?

    if (_.isNaN(a) && _.isNaN(b)) return false;

Compare regular expressions.

    if (_.isRegExp(a) && _.isRegExp(b))
+  };

Perform a deep comparison to check if two objects are equal.

  _.isEqual = function(a, b) {

Check object identity.

    if (a === b) return true;

Different types?

    var atype = typeof(a), btype = typeof(b);
+    if (atype != btype) return false;

Basic equality test (watch out for coercions).

    if (a == b) return true;

One is falsy and the other truthy.

    if ((!a && b) || (a && !b)) return false;

One of them implements an isEqual()?

    if (a.isEqual) return a.isEqual(b);

Check dates' integer values.

    if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();

Both are NaN?

    if (_.isNaN(a) && _.isNaN(b)) return false;

Compare regular expressions.

    if (_.isRegExp(a) && _.isRegExp(b))
       return a.source     === b.source &&
              a.global     === b.global &&
              a.ignoreCase === b.ignoreCase &&
-             a.multiline  === b.multiline;

If a is not an object by this point, we can't handle it.

    if (atype !== 'object') return false;

Check for different array lengths before comparing contents.

    if (a.length && (a.length !== b.length)) return false;

Nothing else worked, deep compare the contents.

    var aKeys = _.keys(a), bKeys = _.keys(b);

Different object sizes?

    if (aKeys.length != bKeys.length) return false;

Recursive comparison of contents.

    for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
+             a.multiline  === b.multiline;

If a is not an object by this point, we can't handle it.

    if (atype !== 'object') return false;

Check for different array lengths before comparing contents.

    if (a.length && (a.length !== b.length)) return false;

Nothing else worked, deep compare the contents.

    var aKeys = _.keys(a), bKeys = _.keys(b);

Different object sizes?

    if (aKeys.length != bKeys.length) return false;

Recursive comparison of contents.

    for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
     return true;
-  };

Is a given array or object empty?

  _.isEmpty = function(obj) {
+  };

Is a given array or object empty?

  _.isEmpty = function(obj) {
     if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
     for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
     return true;
-  };

Is a given value a DOM element?

  _.isElement = function(obj) {
+  };

Is a given value a DOM element?

  _.isElement = function(obj) {
     return !!(obj && obj.nodeType == 1);
-  };

Is a given value an array? + };

Is a given value an array? Delegates to ECMA5's native Array.isArray

  _.isArray = nativeIsArray || function(obj) {
     return !!(obj && obj.concat && obj.unshift && !obj.callee);
-  };

Is a given variable an arguments object?

  _.isArguments = function(obj) {
+  };

Is a given variable an arguments object?

  _.isArguments = function(obj) {
     return !!(obj && obj.callee);
-  };

Is a given value a function?

  _.isFunction = function(obj) {
+  };

Is a given value a function?

  _.isFunction = function(obj) {
     return !!(obj && obj.constructor && obj.call && obj.apply);
-  };

Is a given value a string?

  _.isString = function(obj) {
+  };

Is a given value a string?

  _.isString = function(obj) {
     return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
-  };

Is a given value a number?

  _.isNumber = function(obj) {
-    return (obj === +obj) || (toString.call(obj) === '[object Number]');
-  };

Is a given value a boolean?

  _.isBoolean = function(obj) {
-    return obj === true || obj === false;
-  };

Is a given value a date?

  _.isDate = function(obj) {
-    return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
-  };

Is the given value a regular expression?

  _.isRegExp = function(obj) {
-    return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
-  };

Is the given value NaN -- this one is interesting. NaN != NaN, and + };

Is a given value a number?

  _.isNumber = function(obj) {
+    return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
+  };

Is the given value NaN -- this one is interesting. NaN != NaN, and isNaN(undefined) == true, so we make sure it's a number first.

  _.isNaN = function(obj) {
-    return _.isNumber(obj) && isNaN(obj);
-  };

Is a given value equal to null?

  _.isNull = function(obj) {
+    return toString.call(obj) === '[object Number]' && isNaN(obj);
+  };

Is a given value a boolean?

  _.isBoolean = function(obj) {
+    return obj === true || obj === false;
+  };

Is a given value a date?

  _.isDate = function(obj) {
+    return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
+  };

Is the given value a regular expression?

  _.isRegExp = function(obj) {
+    return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
+  };

Is a given value equal to null?

  _.isNull = function(obj) {
     return obj === null;
-  };

Is a given variable undefined?

  _.isUndefined = function(obj) {
-    return typeof obj == 'undefined';
-  };

Utility Functions

Run Underscore.js in noConflict mode, returning the _ variable to its + };

Is a given variable undefined?

  _.isUndefined = function(obj) {
+    return obj === void 0;
+  };

Utility Functions

Run Underscore.js in noConflict mode, returning the _ variable to its previous owner. Returns a reference to the Underscore object.

  _.noConflict = function() {
     root._ = previousUnderscore;
     return this;
-  };

Keep the identity function around for default iterators.

  _.identity = function(value) {
+  };

Keep the identity function around for default iterators.

  _.identity = function(value) {
     return value;
-  };

Run a function n times.

  _.times = function (n, iterator, context) {
+  };

Run a function n times.

  _.times = function (n, iterator, context) {
     for (var i = 0; i < n; i++) iterator.call(context, i);
-  };

Break out of the middle of an iteration.

  _.breakLoop = function() {
-    throw breaker;
-  };

Add your own custom functions to the Underscore object, ensuring that + };

Add your own custom functions to the Underscore object, ensuring that they're correctly added to the OOP wrapper as well.

  _.mixin = function(obj) {
     each(_.functions(obj), function(name){
       addToWrapper(name, _[name] = obj[name]);
     });
-  };

Generate a unique integer id (unique within the entire client session). + };

Generate a unique integer id (unique within the entire client session). Useful for temporary DOM ids.

  var idCounter = 0;
   _.uniqueId = function(prefix) {
     var id = idCounter++;
     return prefix ? prefix + id : id;
-  };

By default, Underscore uses ERB-style template delimiters, change the + };

By default, Underscore uses ERB-style template delimiters, change the following template settings to use alternative delimiters.

  _.templateSettings = {
     evaluate    : /<%([\s\S]+?)%>/g,
     interpolate : /<%=([\s\S]+?)%>/g
-  };

JavaScript micro-templating, similar to John Resig's implementation. + };

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(str, data) {
     var c  = _.templateSettings;
     var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
       'with(obj||{}){__p.push(\'' +
-      str.replace(/'/g, "\\'")
+      str.replace(/\\/g, '\\\\')
+         .replace(/'/g, "\\'")
          .replace(c.interpolate, function(match, code) {
            return "'," + code.replace(/\\'/g, "'") + ",'";
          })
@@ -384,31 +413,31 @@ and correctly escapes quotes within interpolated code.

The OOP Wrapper

If Underscore is called as a function, it returns a wrapped object that + };

The OOP Wrapper

If Underscore is called as a function, it returns a wrapped object that can be used OO-style. This wrapper holds altered versions of all the -underscore functions. Wrapped objects may be chained.

  var wrapper = function(obj) { this._wrapped = obj; };

Expose wrapper.prototype as _.prototype

  _.prototype = wrapper.prototype;

Helper function to continue chaining intermediate results.

  var result = function(obj, chain) {
+underscore functions. Wrapped objects may be chained.

  var wrapper = function(obj) { this._wrapped = obj; };

Expose wrapper.prototype as _.prototype

  _.prototype = wrapper.prototype;

Helper function to continue chaining intermediate results.

  var result = function(obj, chain) {
     return chain ? _(obj).chain() : obj;
-  };

A method to easily add functions to the OOP wrapper.

  var addToWrapper = function(name, func) {
+  };

A method to easily add functions to the OOP wrapper.

  var addToWrapper = function(name, func) {
     wrapper.prototype[name] = function() {
       var args = slice.call(arguments);
       unshift.call(args, this._wrapped);
       return result(func.apply(_, args), this._chain);
     };
-  };

Add all of the Underscore functions to the wrapper object.

  _.mixin(_);

Add all mutator Array functions to the wrapper.

  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+  };

Add all of the Underscore functions to the wrapper object.

  _.mixin(_);

Add all mutator Array functions to the wrapper.

  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
     var method = ArrayProto[name];
     wrapper.prototype[name] = function() {
       method.apply(this._wrapped, arguments);
       return result(this._wrapped, this._chain);
     };
-  });

Add all accessor Array functions to the wrapper.

  each(['concat', 'join', 'slice'], function(name) {
+  });

Add all accessor Array functions to the wrapper.

  each(['concat', 'join', 'slice'], function(name) {
     var method = ArrayProto[name];
     wrapper.prototype[name] = function() {
       return result(method.apply(this._wrapped, arguments), this._chain);
     };
-  });

Start chaining a wrapped Underscore object.

  wrapper.prototype.chain = function() {
+  });

Start chaining a wrapped Underscore object.

  wrapper.prototype.chain = function() {
     this._chain = true;
     return this;
-  };

Extracts the result from a wrapped and chained object.

  wrapper.prototype.value = function() {
+  };

Extracts the result from a wrapped and chained object.

  wrapper.prototype.value = function() {
     return this._wrapped;
   };
 
diff --git a/index.html b/index.html
index 1aa926969..e1d2cb68b 100644
--- a/index.html
+++ b/index.html
@@ -105,7 +105,7 @@
       The project is
       hosted on GitHub.
       You can report bugs and discuss features on the
-      issues page,
+      issues page,
       on Freenode in the #documentcloud channel,
       or send tweets to @documentcloud.
     

@@ -118,11 +118,11 @@ - - + + - +
Development Version (1.1.2)25kb, Uncompressed with CommentsDevelopment Version (1.1.3)26kb, Uncompressed with Comments
Production Version (1.1.2)Production Version (1.1.3) 3kb, Packed and Gzipped
@@ -159,6 +159,7 @@
bind, bindAll, memoize, delay, defer, + throttle, debounce, wrap, compose

@@ -180,8 +181,8 @@
noConflict, identity, times, - breakLoop, mixin, - uniqueId, template + mixin, uniqueId, + template

@@ -249,8 +250,7 @@ _(lyrics).chain() function. The iterator is bound to the context object, if one is passed. Each invocation of iterator is called with three arguments: (element, index, list). If list is a JavaScript object, iterator's - arguments will be (value, key, list). Use breakLoop - to break out of the iteration. Delegates to the native + arguments will be (value, key, list). Delegates to the native forEach function if it exists.

@@ -707,6 +707,33 @@ _.delay(log, 1000, 'logged later');
       
 _.defer(function(){ alert('deferred'); });
 // Returns from the function before the alert runs.
+
+ +

+ throttle_.throttle(function, wait) +
+ Returns a throttled version of the function, that, when invoked repeatedly, + will only actually call the wrapped function at most once per every wait + milliseconds. Useful for rate-limiting events that occur faster than you + can keep up with. +

+
+var throttled = _.throttle(updatePosition, 100);
+$(window).scroll(throttled);
+
+ +

+ debounce_.debounce(function, wait) +
+ Repeated calls to a debounced function will postpone it's execution + until after wait milliseconds have elapsed. Useful for implementing + behavior that should only happen after the input has stopped arriving. + For example: rendering a preview of a Markdown comment, recalculating a + layout after the window has stopped being resized... +

+
+var lazyLayout _.debounce(calculateLayout, 300);
+$(window).resize(lazyLayout);
 

@@ -1006,22 +1033,6 @@ moe === _.identity(moe);

 _(3).times(function(){ genie.grantWish(); });
-

- breakLoop_.breakLoop() -
- Breaks out of the current loop iteration. Similar to the break - keyword in regular "for" loop, but works within an iterator function. - Uses the native StopIteration object in JavaScript 1.7 compliant - browsers. -

-
-var result = null;
-_.each([1, 2, 3], function(num) {
-  if ((result = num) == 2) _.breakLoop();
-});
-result;
-=> 2
-

mixin_.mixin(object)
@@ -1170,6 +1181,21 @@ _([1, 2, 3]).value();

Change Log

+

+ 1.1.3Dec 1, 2010
+ In CommonJS, Underscore may now be required with just:
+ var _ = require("underscore"). + Added _.throttle and _.debounce functions. + Removed _.breakLoop, in favor of an ECMA5-style un-break-able + each implementation — this removes the try/catch, and you'll now have + better stack traces for exceptions that are thrown within an Underscore iterator. + Improved the isType family of functions for better interoperability + with Internet Explorer host objects. + _.template now correctly escapes backslashes in templates. + Improved _.reduce compatibility with the ECMA5 version: + if you don't pass an initial value, the first item in the collection is used. +

+

1.1.2
Fixed _.contains, which was mistakenly pointing at diff --git a/package.json b/package.json index c5277099c..9e9aa2980 100644 --- a/package.json +++ b/package.json @@ -8,5 +8,5 @@ "dependencies" : [], "lib" : ".", "main" : "underscore.js", - "version" : "1.1.2" + "version" : "1.1.3" } diff --git a/underscore-min.js b/underscore-min.js index b800015b8..2979243e0 100644 --- a/underscore-min.js +++ b/underscore-min.js @@ -1,24 +1,25 @@ -// Underscore.js 1.1.2 +// Underscore.js 1.1.3 // (c) 2010 Jeremy Ashkenas, DocumentCloud Inc. // Underscore is freely distributable under the MIT license. // Portions of Underscore are inspired or borrowed from Prototype, // Oliver Steele's Functional, and John Resig's Micro-Templating. // For all details and documentation: // http://documentcloud.github.com/underscore -(function(){var o=this,A=o._,r=typeof StopIteration!=="undefined"?StopIteration:"__break__",k=Array.prototype,m=Object.prototype,i=k.slice,B=k.unshift,C=m.toString,p=m.hasOwnProperty,s=k.forEach,t=k.map,u=k.reduce,v=k.reduceRight,w=k.filter,x=k.every,y=k.some,n=k.indexOf,z=k.lastIndexOf;m=Array.isArray;var D=Object.keys,c=function(a){return new l(a)};if(typeof exports!=="undefined")exports._=c;o._=c;c.VERSION="1.1.2";var j=c.each=c.forEach=function(a,b,d){try{if(s&&a.forEach===s)a.forEach(b,d);else if(c.isNumber(a.length))for(var e= -0,f=a.length;e=e.computed&&(e={value:f,computed:g})});return e.value};c.min=function(a,b,d){if(!b&&c.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};j(a,function(f,g,h){g=b?b.call(d,f,g,h):f;g=e.computed&&(e={value:f,computed:g})});return e.value};c.min=function(a,b,d){if(!b&&c.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};k(a,function(f,g,h){g=b?b.call(d,f,g,h):f;gh?1:0}),"value")};c.sortedIndex=function(a,b,d){d=d||c.identity;for(var e=0,f=a.length;e>1;d(a[g])=0})})};c.zip=function(){for(var a=i.call(arguments),b=c.max(c.pluck(a,"length")),d=Array(b),e=0;e=0})})};c.zip=function(){for(var a=i.call(arguments),b=c.max(c.pluck(a,"length")),d=Array(b),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};c.keys=D||function(a){if(c.isArray(a))return c.range(0,a.length);var b=[],d;for(d in a)if(p.call(a,d))b[b.length]=d;return b};c.values=function(a){return c.map(a,c.identity)};c.functions=c.methods=function(a){return c.filter(c.keys(a),function(b){return c.isFunction(a[b])}).sort()};c.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]}); -return a};c.clone=function(a){return c.isArray(a)?a.slice():c.extend({},a)};c.tap=function(a,b){b(a);return a};c.isEqual=function(a,b){if(a===b)return true;var d=typeof a;if(d!=typeof b)return false;if(a==b)return true;if(!a&&b||a&&!b)return false;if(a.isEqual)return a.isEqual(b);if(c.isDate(a)&&c.isDate(b))return a.getTime()===b.getTime();if(c.isNaN(a)&&c.isNaN(b))return false;if(c.isRegExp(a)&&c.isRegExp(b))return a.source===b.source&&a.global===b.global&&a.ignoreCase===b.ignoreCase&&a.multiline=== -b.multiline;if(d!=="object")return false;if(a.length&&a.length!==b.length)return false;d=c.keys(a);var e=c.keys(b);if(d.length!=e.length)return false;for(var f in a)if(!(f in b)||!c.isEqual(a[f],b[f]))return false;return true};c.isEmpty=function(a){if(c.isArray(a)||c.isString(a))return a.length===0;for(var b in a)if(p.call(a,b))return false;return true};c.isElement=function(a){return!!(a&&a.nodeType==1)};c.isArray=m||function(a){return!!(a&&a.concat&&a.unshift&&!a.callee)};c.isArguments=function(a){return!!(a&& -a.callee)};c.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};c.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};c.isNumber=function(a){return a===+a||C.call(a)==="[object Number]"};c.isBoolean=function(a){return a===true||a===false};c.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};c.isRegExp=function(a){return!!(a&&a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};c.isNaN=function(a){return c.isNumber(a)&&isNaN(a)};c.isNull=function(a){return a=== -null};c.isUndefined=function(a){return typeof a=="undefined"};c.noConflict=function(){o._=A;return this};c.identity=function(a){return a};c.times=function(a,b,d){for(var e=0;e/g,interpolate:/<%=([\s\S]+?)%>/g};c.template=function(a,b){var d=c.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+ -a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate,function(e,f){return"',"+f.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(e,f){return"');"+f.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";d=new Function("obj",d);return b?d(b):d};var l=function(a){this._wrapped=a};c.prototype=l.prototype;var q=function(a,b){return b?c(a).chain():a},F=function(a,b){l.prototype[a]=function(){var d= -i.call(arguments);B.call(d,this._wrapped);return q(b.apply(c,d),this._chain)}};c.mixin(c);j(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=k[a];l.prototype[a]=function(){b.apply(this._wrapped,arguments);return q(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];l.prototype[a]=function(){return q(b.apply(this._wrapped,arguments),this._chain)}});l.prototype.chain=function(){this._chain=true;return this};l.prototype.value=function(){return this._wrapped}})(); +0)b=c.functions(a);k(b,function(d){a[d]=c.bind(a[d],a)});return a};c.memoize=function(a,b){var d={};b=b||c.identity;return function(){var e=b.apply(this,arguments);return e in d?d[e]:d[e]=a.apply(this,arguments)}};c.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};c.defer=function(a){return c.delay.apply(c,[a,1].concat(i.call(arguments,1)))};var B=function(a,b,d){var e;return function(){var f=this,g=arguments,h=function(){e=null;a.apply(f,g)};d&& +clearTimeout(e);if(d||!e)e=setTimeout(h,b)}};c.throttle=function(a,b){return B(a,b,false)};c.debounce=function(a,b){return B(a,b,true)};c.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments));return b.apply(b,d)}};c.compose=function(){var a=i.call(arguments);return function(){for(var b=i.call(arguments),d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};c.keys=F||function(a){if(c.isArray(a))return c.range(0,a.length);var b=[],d;for(d in a)if(q.call(a,d))b[b.length]=d;return b}; +c.values=function(a){return c.map(a,c.identity)};c.functions=c.methods=function(a){return c.filter(c.keys(a),function(b){return c.isFunction(a[b])}).sort()};c.extend=function(a){k(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};c.clone=function(a){return c.isArray(a)?a.slice():c.extend({},a)};c.tap=function(a,b){b(a);return a};c.isEqual=function(a,b){if(a===b)return true;var d=typeof a;if(d!=typeof b)return false;if(a==b)return true;if(!a&&b||a&&!b)return false;if(a.isEqual)return a.isEqual(b); +if(c.isDate(a)&&c.isDate(b))return a.getTime()===b.getTime();if(c.isNaN(a)&&c.isNaN(b))return false;if(c.isRegExp(a)&&c.isRegExp(b))return a.source===b.source&&a.global===b.global&&a.ignoreCase===b.ignoreCase&&a.multiline===b.multiline;if(d!=="object")return false;if(a.length&&a.length!==b.length)return false;d=c.keys(a);var e=c.keys(b);if(d.length!=e.length)return false;for(var f in a)if(!(f in b)||!c.isEqual(a[f],b[f]))return false;return true};c.isEmpty=function(a){if(c.isArray(a)||c.isString(a))return a.length=== +0;for(var b in a)if(q.call(a,b))return false;return true};c.isElement=function(a){return!!(a&&a.nodeType==1)};c.isArray=n||function(a){return!!(a&&a.concat&&a.unshift&&!a.callee)};c.isArguments=function(a){return!!(a&&a.callee)};c.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};c.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};c.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)};c.isNaN=function(a){return E.call(a)==="[object Number]"&&isNaN(a)}; +c.isBoolean=function(a){return a===true||a===false};c.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};c.isRegExp=function(a){return!!(a&&a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};c.isNull=function(a){return a===null};c.isUndefined=function(a){return a===void 0};c.noConflict=function(){p._=C;return this};c.identity=function(a){return a};c.times=function(a,b,d){for(var e=0;e/g,interpolate:/<%=([\s\S]+?)%>/g};c.template=function(a,b){var d=c.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate,function(e,f){return"',"+f.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(e,f){return"');"+f.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g, +"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";d=new Function("obj",d);return b?d(b):d};var l=function(a){this._wrapped=a};c.prototype=l.prototype;var r=function(a,b){return b?c(a).chain():a},H=function(a,b){l.prototype[a]=function(){var d=i.call(arguments);D.call(d,this._wrapped);return r(b.apply(c,d),this._chain)}};c.mixin(c);k(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=j[a];l.prototype[a]=function(){b.apply(this._wrapped,arguments); +return r(this._wrapped,this._chain)}});k(["concat","join","slice"],function(a){var b=j[a];l.prototype[a]=function(){return r(b.apply(this._wrapped,arguments),this._chain)}});l.prototype.chain=function(){this._chain=true;return this};l.prototype.value=function(){return this._wrapped}})(); diff --git a/underscore.js b/underscore.js index 424a87bdd..887d039c3 100644 --- a/underscore.js +++ b/underscore.js @@ -1,4 +1,4 @@ -// Underscore.js 1.1.2 +// Underscore.js 1.1.3 // (c) 2010 Jeremy Ashkenas, DocumentCloud Inc. // Underscore is freely distributable under the MIT license. // Portions of Underscore are inspired or borrowed from Prototype, @@ -58,7 +58,7 @@ } // Current version. - _.VERSION = '1.1.2'; + _.VERSION = '1.1.3'; // Collection Functions // --------------------