diff --git a/bower.json b/bower.json index 2d3e0291c..82acb5c77 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "underscore", - "version": "1.6.0", + "version": "1.7.0", "main": "underscore.js", "keywords": ["util", "functional", "server", "client", "browser"], "ignore" : ["docs", "test", "*.yml", "CNAME", "index.html", "favicon.ico", "CONTRIBUTING.md"] diff --git a/component.json b/component.json index bb1775e70..47d145086 100644 --- a/component.json +++ b/component.json @@ -5,6 +5,6 @@ "repo" : "jashkenas/underscore", "main" : "underscore.js", "scripts" : ["underscore.js"], - "version" : "1.6.0", + "version" : "1.7.0", "license" : "MIT" } diff --git a/docs/underscore.html b/docs/underscore.html index 014d5dece..9ac964368 100644 --- a/docs/underscore.html +++ b/docs/underscore.html @@ -27,7 +27,7 @@

underscore.js

-
Underscore.js 1.6.0
+              
Underscore.js 1.7.0
 http://underscorejs.org
 (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
 Underscore may be freely distributed under the MIT license.
@@ -35,7 +35,7 @@ 

underscore.js

-(function() {
+(function() {
@@ -101,21 +101,6 @@

Baseline setup

-

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

- - - -
  var breaker = {};
- - - - -
  • -
    - -
    - -

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

    @@ -125,11 +110,11 @@

    Baseline setup

  • -
  • +
  • - +

    Create quick reference variables for speed access to core prototypes.

    @@ -145,11 +130,11 @@

    Baseline setup

  • -
  • +
  • - +

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

    @@ -157,15 +142,6 @@

    Baseline setup

      var
    -    nativeForEach      = ArrayProto.forEach,
    -    nativeMap          = ArrayProto.map,
    -    nativeReduce       = ArrayProto.reduce,
    -    nativeReduceRight  = ArrayProto.reduceRight,
    -    nativeFilter       = ArrayProto.filter,
    -    nativeEvery        = ArrayProto.every,
    -    nativeSome         = ArrayProto.some,
    -    nativeIndexOf      = ArrayProto.indexOf,
    -    nativeLastIndexOf  = ArrayProto.lastIndexOf,
         nativeIsArray      = Array.isArray,
         nativeKeys         = Object.keys,
         nativeBind         = FuncProto.bind;
    @@ -173,17 +149,17 @@

    Baseline setup

  • -
  • +
  • - +

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

    -
      var _ = function(obj) {
    +            
      var _ = function(obj) {
         if (obj instanceof _) return obj;
         if (!(this instanceof _)) return new _(obj);
         this._wrapped = obj;
    @@ -192,22 +168,21 @@ 

    Baseline setup

  • -
  • +
  • - +

    Export the Underscore object for Node.js, with backwards-compatibility for the old require() API. If we’re in -the browser, add _ as a global object via a string identifier, -for Closure Compiler “advanced” mode.

    +the browser, add _ as a global object.

      if (typeof exports !== 'undefined') {
    -    if (typeof module !== 'undefined' && module.exports) {
    -      exports = module.exports = _;
    +    if (typeof module !== 'undefined' && module.exports) {
    +      exports = module.exports = _;
         }
         exports._ = _;
       } else {
    @@ -217,11 +192,11 @@ 

    Baseline setup

  • -
  • +
  • - +

    Current version.

    @@ -232,16 +207,61 @@

    Baseline setup

  • +
  • +
    + +
    + +
    +

    Internal function that returns an efficient (for current engines) version +of the passed-in callback, to be repeatedly applied in other Underscore +functions.

    + +
    + +
      var createCallback = function(func, context, argCount) {
    +    if (context === void 0) return func;
    +    switch (argCount == null ? 3 : argCount) {
    +      case 1: return function(value) {
    +        return func.call(context, value);
    +      };
    +      case 2: return function(value, other) {
    +        return func.call(context, value, other);
    +      };
    +      case 3: return function(value, index, collection) {
    +        return func.call(context, value, index, collection);
    +      };
    +      case 4: return function(accumulator, value, index, collection) {
    +        return func.call(context, accumulator, value, index, collection);
    +      };
    +    }
    +    return function() {
    +      return func.apply(context, arguments);
    +    };
    +  };
    + +
  • + +
  • -

    Collection Functions

    +

    A mostly-internal function to generate callbacks that can be applied +to each element in a collection, returning the desired result — either +identity, an arbitrary callback, a property matcher, or a property accessor.

    +
      _.iteratee = function(value, context, argCount) {
    +    if (value == null) return _.identity;
    +    if (_.isFunction(value)) return createCallback(value, context, argCount);
    +    if (_.isObject(value)) return _.matches(value);
    +    return _.property(value);
    +  };
    +
  • @@ -251,7 +271,8 @@

    Collection Functions

    - +

    Collection Functions

    + @@ -263,24 +284,36 @@

    Collection Functions

    + + + + + + +
  • +
    + +
    + +

    The cornerstone, an each implementation, aka forEach. -Handles objects with the built-in forEach, arrays, and raw objects. -Delegates to ECMAScript 5‘s native forEach if available.

    +Handles raw objects in addition to array-likes. Treats all +sparse array-likes as if they were dense.

    -
      var each = _.each = _.forEach = function(obj, iterator, context) {
    +            
      _.each = _.forEach = function(obj, iteratee, context) {
         if (obj == null) return obj;
    -    if (nativeForEach && obj.forEach === nativeForEach) {
    -      obj.forEach(iterator, context);
    -    } else if (obj.length === +obj.length) {
    -      for (var i = 0, length = obj.length; i < length; i++) {
    -        if (iterator.call(context, obj[i], i, obj) === breaker) return;
    +    iteratee = createCallback(iteratee, context);
    +    var i, length = obj.length;
    +    if (length === +length) {
    +      for (i = 0; i < length; i++) {
    +        iteratee(obj[i], i, obj);
           }
         } else {
           var keys = _.keys(obj);
    -      for (var i = 0, length = keys.length; i < length; i++) {
    -        if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
    +      for (i = 0, length = keys.length; i < length; i++) {
    +        iteratee(obj[keys[i]], keys[i], obj);
           }
         }
         return obj;
    @@ -289,24 +322,27 @@ 

    Collection Functions

  • -
  • +
  • - +
    -

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

    +

    Return the results of applying the iteratee to each element.

    -
      _.map = _.collect = function(obj, iterator, context) {
    -    var results = [];
    -    if (obj == null) return results;
    -    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
    -    each(obj, function(value, index, list) {
    -      results.push(iterator.call(context, value, index, list));
    -    });
    +            
      _.map = _.collect = function(obj, iteratee, context) {
    +    if (obj == null) return [];
    +    iteratee = _.iteratee(iteratee, context);
    +    var keys = obj.length !== +obj.length && _.keys(obj),
    +        length = (keys || obj).length,
    +        results = Array(length),
    +        currentKey;
    +    for (var index = 0; index < length; index++) {
    +      currentKey = keys ? keys[index] : index;
    +      results[index] = iteratee(obj[currentKey], currentKey, obj);
    +    }
         return results;
       };
     
    @@ -315,92 +351,82 @@ 

    Collection Functions

  • -
  • +
  • - +

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

    +or foldl.

    -
      _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
    -    var initial = arguments.length > 2;
    +            
      _.reduce = _.foldl = _.inject = function(obj, iteratee, memo, context) {
         if (obj == null) obj = [];
    -    if (nativeReduce && obj.reduce === nativeReduce) {
    -      if (context) iterator = _.bind(iterator, context);
    -      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
    +    iteratee = createCallback(iteratee, context, 4);
    +    var keys = obj.length !== +obj.length && _.keys(obj),
    +        length = (keys || obj).length,
    +        index = 0, currentKey;
    +    if (arguments.length < 3) {
    +      if (!length) throw new TypeError(reduceError);
    +      memo = obj[keys ? keys[index++] : index++];
    +    }
    +    for (; index < length; index++) {
    +      currentKey = keys ? keys[index] : index;
    +      memo = iteratee(memo, obj[currentKey], currentKey, obj);
         }
    -    each(obj, function(value, index, list) {
    -      if (!initial) {
    -        memo = value;
    -        initial = true;
    -      } else {
    -        memo = iterator.call(context, memo, value, index, list);
    -      }
    -    });
    -    if (!initial) throw new TypeError(reduceError);
         return memo;
       };
  • -
  • +
  • - +
    -

    The right-associative version of reduce, also known as foldr. -Delegates to ECMAScript 5‘s native reduceRight if available.

    +

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

    -
      _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
    -    var initial = arguments.length > 2;
    +            
      _.reduceRight = _.foldr = function(obj, iteratee, memo, context) {
         if (obj == null) obj = [];
    -    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
    -      if (context) iterator = _.bind(iterator, context);
    -      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
    +    iteratee = createCallback(iteratee, context, 4);
    +    var keys = obj.length !== + obj.length && _.keys(obj),
    +        index = (keys || obj).length,
    +        currentKey;
    +    if (arguments.length < 3) {
    +      if (!index) throw new TypeError(reduceError);
    +      memo = obj[keys ? keys[--index] : --index];
         }
    -    var length = obj.length;
    -    if (length !== +length) {
    -      var keys = _.keys(obj);
    -      length = keys.length;
    +    while (index--) {
    +      currentKey = keys ? keys[index] : index;
    +      memo = iteratee(memo, obj[currentKey], currentKey, obj);
         }
    -    each(obj, function(value, index, list) {
    -      index = keys ? keys[--length] : --length;
    -      if (!initial) {
    -        memo = obj[index];
    -        initial = true;
    -      } else {
    -        memo = iterator.call(context, memo, obj[index], index, list);
    -      }
    -    });
    -    if (!initial) throw new TypeError(reduceError);
         return memo;
       };
  • -
  • +
  • - +

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

    -
      _.find = _.detect = function(obj, predicate, context) {
    +            
      _.find = _.detect = function(obj, predicate, context) {
         var result;
    -    any(obj, function(value, index, list) {
    -      if (predicate.call(context, value, index, list)) {
    +    predicate = _.iteratee(predicate, context);
    +    _.some(obj, function(value, index, list) {
    +      if (predicate(value, index, list)) {
             result = value;
             return true;
           }
    @@ -411,24 +437,23 @@ 

    Collection Functions

  • -
  • +
  • - +

    Return all the elements that pass a truth test. -Delegates to ECMAScript 5‘s native filter if available. Aliased as select.

    -
      _.filter = _.select = function(obj, predicate, context) {
    +            
      _.filter = _.select = function(obj, predicate, context) {
         var results = [];
         if (obj == null) return results;
    -    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context);
    -    each(obj, function(value, index, list) {
    -      if (predicate.call(context, value, index, list)) results.push(value);
    +    predicate = _.iteratee(predicate, context);
    +    _.each(obj, function(value, index, list) {
    +      if (predicate(value, index, list)) results.push(value);
         });
         return results;
       };
    @@ -436,113 +461,111 @@

    Collection Functions

  • -
  • +
  • - +

    Return all the elements for which a truth test fails.

    -
      _.reject = function(obj, predicate, context) {
    -    return _.filter(obj, function(value, index, list) {
    -      return !predicate.call(context, value, index, list);
    -    }, context);
    +            
      _.reject = function(obj, predicate, context) {
    +    return _.filter(obj, _.negate(_.iteratee(predicate)), context);
       };
  • -
  • +
  • - +

    Determine whether all of the elements match a truth test. -Delegates to ECMAScript 5‘s native every if available. Aliased as all.

    -
      _.every = _.all = function(obj, predicate, context) {
    -    predicate || (predicate = _.identity);
    -    var result = true;
    -    if (obj == null) return result;
    -    if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context);
    -    each(obj, function(value, index, list) {
    -      if (!(result = result && predicate.call(context, value, index, list))) return breaker;
    -    });
    -    return !!result;
    +            
      _.every = _.all = function(obj, predicate, context) {
    +    if (obj == null) return true;
    +    predicate = _.iteratee(predicate, context);
    +    var keys = obj.length !== +obj.length && _.keys(obj),
    +        length = (keys || obj).length,
    +        index, currentKey;
    +    for (index = 0; index < length; index++) {
    +      currentKey = keys ? keys[index] : index;
    +      if (!predicate(obj[currentKey], currentKey, obj)) return false;
    +    }
    +    return true;
       };
  • -
  • +
  • - +

    Determine if at least one element in the object matches a truth test. -Delegates to ECMAScript 5‘s native some if available. Aliased as any.

    -
      var any = _.some = _.any = function(obj, predicate, context) {
    -    predicate || (predicate = _.identity);
    -    var result = false;
    -    if (obj == null) return result;
    -    if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context);
    -    each(obj, function(value, index, list) {
    -      if (result || (result = predicate.call(context, value, index, list))) return breaker;
    -    });
    -    return !!result;
    +            
      _.some = _.any = function(obj, predicate, context) {
    +    if (obj == null) return false;
    +    predicate = _.iteratee(predicate, context);
    +    var keys = obj.length !== +obj.length && _.keys(obj),
    +        length = (keys || obj).length,
    +        index, currentKey;
    +    for (index = 0; index < length; index++) {
    +      currentKey = keys ? keys[index] : index;
    +      if (predicate(obj[currentKey], currentKey, obj)) return true;
    +    }
    +    return false;
       };
  • -
  • +
  • - +

    Determine if the array or object contains a given value (using ===). Aliased as include.

    -
      _.contains = _.include = function(obj, target) {
    +            
      _.contains = _.include = function(obj, target) {
         if (obj == null) return false;
    -    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
    -    return any(obj, function(value) {
    -      return value === target;
    -    });
    +    if (obj.length !== +obj.length) obj = _.values(obj);
    +    return _.indexOf(obj, target) >= 0;
       };
  • -
  • +
  • - +

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

    -
      _.invoke = function(obj, method) {
    +            
      _.invoke = function(obj, method) {
         var args = slice.call(arguments, 2);
         var isFunc = _.isFunction(method);
    -    return _.map(obj, function(value) {
    +    return _.map(obj, function(value) {
           return (isFunc ? method : value[method]).apply(value, args);
         });
       };
    @@ -550,148 +573,164 @@

    Collection Functions

  • -
  • +
  • - +

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

    -
      _.pluck = function(obj, key) {
    +            
      _.pluck = function(obj, key) {
         return _.map(obj, _.property(key));
       };
  • -
  • +
  • - +

    Convenience version of a common use case of filter: selecting only objects containing specific key:value pairs.

    -
      _.where = function(obj, attrs) {
    +            
      _.where = function(obj, attrs) {
         return _.filter(obj, _.matches(attrs));
       };
  • -
  • +
  • - +

    Convenience version of a common use case of find: getting the first object containing specific key:value pairs.

    -
      _.findWhere = function(obj, attrs) {
    +            
      _.findWhere = function(obj, attrs) {
         return _.find(obj, _.matches(attrs));
       };
  • -
  • +
  • - +
    -

    Return the maximum element or (element-based computation). -Can’t optimize arrays of integers longer than 65,535 elements. -See WebKit Bug 80797

    +

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

    -
      _.max = function(obj, iterator, context) {
    -    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
    -      return Math.max.apply(Math, obj);
    -    }
    -    var result = -Infinity, lastComputed = -Infinity;
    -    each(obj, function(value, index, list) {
    -      var computed = iterator ? iterator.call(context, value, index, list) : value;
    -      if (computed > lastComputed) {
    -        result = value;
    -        lastComputed = computed;
    +            
      _.max = function(obj, iteratee, context) {
    +    var result = -Infinity, lastComputed = -Infinity,
    +        value, computed;
    +    if (iteratee == null && obj != null) {
    +      obj = obj.length === +obj.length ? obj : _.values(obj);
    +      for (var i = 0, length = obj.length; i < length; i++) {
    +        value = obj[i];
    +        if (value > result) {
    +          result = value;
    +        }
           }
    -    });
    +    } else {
    +      iteratee = _.iteratee(iteratee, context);
    +      _.each(obj, function(value, index, list) {
    +        computed = iteratee(value, index, list);
    +        if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
    +          result = value;
    +          lastComputed = computed;
    +        }
    +      });
    +    }
         return result;
       };
  • -
  • +
  • - +

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

    -
      _.min = function(obj, iterator, context) {
    -    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
    -      return Math.min.apply(Math, obj);
    -    }
    -    var result = Infinity, lastComputed = Infinity;
    -    each(obj, function(value, index, list) {
    -      var computed = iterator ? iterator.call(context, value, index, list) : value;
    -      if (computed < lastComputed) {
    -        result = value;
    -        lastComputed = computed;
    +            
      _.min = function(obj, iteratee, context) {
    +    var result = Infinity, lastComputed = Infinity,
    +        value, computed;
    +    if (iteratee == null && obj != null) {
    +      obj = obj.length === +obj.length ? obj : _.values(obj);
    +      for (var i = 0, length = obj.length; i < length; i++) {
    +        value = obj[i];
    +        if (value < result) {
    +          result = value;
    +        }
           }
    -    });
    +    } else {
    +      iteratee = _.iteratee(iteratee, context);
    +      _.each(obj, function(value, index, list) {
    +        computed = iteratee(value, index, list);
    +        if (computed < lastComputed || computed === Infinity && result === Infinity) {
    +          result = value;
    +          lastComputed = computed;
    +        }
    +      });
    +    }
         return result;
       };
  • -
  • +
  • - +
    -

    Shuffle an array, using the modern version of the +

    Shuffle a collection, using the modern version of the Fisher-Yates shuffle.

    -
      _.shuffle = function(obj) {
    -    var rand;
    -    var index = 0;
    -    var shuffled = [];
    -    each(obj, function(value) {
    -      rand = _.random(index++);
    -      shuffled[index - 1] = shuffled[rand];
    -      shuffled[rand] = value;
    -    });
    +            
      _.shuffle = function(obj) {
    +    var set = obj && obj.length === +obj.length ? obj : _.values(obj);
    +    var length = set.length;
    +    var shuffled = Array(length);
    +    for (var index = 0, rand; index < length; index++) {
    +      rand = _.random(0, index);
    +      if (rand !== index) shuffled[index] = shuffled[rand];
    +      shuffled[rand] = set[index];
    +    }
         return shuffled;
       };
  • -
  • +
  • - +

    Sample n random values from a collection. If n is not specified, returns a single random element. @@ -699,7 +738,7 @@

    Collection Functions

    -
      _.sample = function(obj, n, guard) {
    +            
      _.sample = function(obj, n, guard) {
         if (n == null || guard) {
           if (obj.length !== +obj.length) obj = _.values(obj);
           return obj[_.random(obj.length - 1)];
    @@ -710,44 +749,25 @@ 

    Collection Functions

  • -
  • -
    - -
    - -
    -

    An internal function to generate lookup iterators.

    - -
    - -
      var lookupIterator = function(value) {
    -    if (value == null) return _.identity;
    -    if (_.isFunction(value)) return value;
    -    return _.property(value);
    -  };
    - -
  • - -
  • -

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

    +

    Sort the object’s values by a criterion produced by an iteratee.

    -
      _.sortBy = function(obj, iterator, context) {
    -    iterator = lookupIterator(iterator);
    -    return _.pluck(_.map(obj, function(value, index, list) {
    +            
      _.sortBy = function(obj, iteratee, context) {
    +    iteratee = _.iteratee(iteratee, context);
    +    return _.pluck(_.map(obj, function(value, index, list) {
           return {
             value: value,
             index: index,
    -        criteria: iterator.call(context, value, index, list)
    +        criteria: iteratee(value, index, list)
           };
    -    }).sort(function(left, right) {
    +    }).sort(function(left, right) {
           var a = left.criteria;
           var b = right.criteria;
           if (a !== b) {
    @@ -771,13 +791,13 @@ 

    Collection Functions

    -
      var group = function(behavior) {
    -    return function(obj, iterator, context) {
    +            
      var group = function(behavior) {
    +    return function(obj, iteratee, context) {
           var result = {};
    -      iterator = lookupIterator(iterator);
    -      each(obj, function(value, index) {
    -        var key = iterator.call(context, value, index, obj);
    -        behavior(result, key, value);
    +      iteratee = _.iteratee(iteratee, context);
    +      _.each(obj, function(value, index) {
    +        var key = iteratee(value, index, obj);
    +        behavior(result, value, key);
           });
           return result;
         };
    @@ -797,8 +817,8 @@ 

    Collection Functions

    -
      _.groupBy = group(function(result, key, value) {
    -    _.has(result, key) ? result[key].push(value) : result[key] = [value];
    +            
      _.groupBy = group(function(result, value, key) {
    +    if (_.has(result, key)) result[key].push(value); else result[key] = [value];
       });
  • @@ -815,7 +835,7 @@

    Collection Functions

    -
      _.indexBy = group(function(result, key, value) {
    +            
      _.indexBy = group(function(result, value, key) {
         result[key] = value;
       });
    @@ -834,8 +854,8 @@

    Collection Functions

    -
      _.countBy = group(function(result, key) {
    -    _.has(result, key) ? result[key]++ : result[key] = 1;
    +            
      _.countBy = group(function(result, value, key) {
    +    if (_.has(result, key)) result[key]++; else result[key] = 1;
       });
    @@ -852,13 +872,13 @@

    Collection Functions

    -
      _.sortedIndex = function(array, obj, iterator, context) {
    -    iterator = lookupIterator(iterator);
    -    var value = iterator.call(context, obj);
    +            
      _.sortedIndex = function(array, obj, iteratee, context) {
    +    iteratee = _.iteratee(iteratee, context, 1);
    +    var value = iteratee(obj);
         var low = 0, high = array.length;
         while (low < high) {
    -      var mid = (low + high) >>> 1;
    -      iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
    +      var mid = low + high >>> 1;
    +      if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
         }
         return low;
       };
    @@ -876,7 +896,7 @@

    Collection Functions

    -
      _.toArray = function(obj) {
    +            
      _.toArray = function(obj) {
         if (!obj) return [];
         if (_.isArray(obj)) return slice.call(obj);
         if (obj.length === +obj.length) return _.map(obj, _.identity);
    @@ -896,9 +916,9 @@ 

    Collection Functions

    -
      _.size = function(obj) {
    +            
      _.size = function(obj) {
         if (obj == null) return 0;
    -    return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
    +    return obj.length === +obj.length ? obj.length : _.keys(obj).length;
       };
    @@ -910,10 +930,20 @@

    Collection Functions

    -

    Array Functions

    +

    Split a collection into two arrays: one whose elements all satisfy the given +predicate, and one whose elements all do not satisfy the predicate.

    +
      _.partition = function(obj, predicate, context) {
    +    predicate = _.iteratee(predicate, context);
    +    var pass = [], fail = [];
    +    _.each(obj, function(value, key, obj) {
    +      (predicate(value, key, obj) ? pass : fail).push(value);
    +    });
    +    return [pass, fail];
    +  };
    + @@ -923,7 +953,8 @@

    Array Functions

    - +

    Array Functions

    +
    @@ -935,15 +966,27 @@

    Array Functions

    + +
    + + + + +
  • +
    + +
    + +

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

    -
      _.first = _.head = _.take = function(array, n, guard) {
    +            
      _.first = _.head = _.take = function(array, n, guard) {
         if (array == null) return void 0;
    -    if ((n == null) || guard) return array[0];
    +    if (n == null || guard) return array[0];
         if (n < 0) return [];
         return slice.call(array, 0, n);
       };
    @@ -951,11 +994,11 @@

    Array Functions

  • -
  • +
  • - +

    Returns everything but the last entry of the array. Especially useful on the arguments object. Passing n will return all the values in @@ -964,38 +1007,38 @@

    Array Functions

    -
      _.initial = function(array, n, guard) {
    -    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
    +            
      _.initial = function(array, n, guard) {
    +    return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
       };
  • -
  • +
  • - +

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

    -
      _.last = function(array, n, guard) {
    +            
      _.last = function(array, n, guard) {
         if (array == null) return void 0;
    -    if ((n == null) || guard) return array[array.length - 1];
    +    if (n == null || guard) return array[array.length - 1];
         return slice.call(array, Math.max(array.length - n, 0));
       };
  • -
  • +
  • - +

    Returns everything but the first entry of the array. Aliased as tail and drop. Especially useful on the arguments object. Passing an n will return @@ -1004,114 +1047,95 @@

    Array Functions

    -
      _.rest = _.tail = _.drop = function(array, n, guard) {
    -    return slice.call(array, (n == null) || guard ? 1 : n);
    +            
      _.rest = _.tail = _.drop = function(array, n, guard) {
    +    return slice.call(array, n == null || guard ? 1 : n);
       };
  • -
  • +
  • - +

    Trim out all falsy values from an array.

    -
      _.compact = function(array) {
    +            
      _.compact = function(array) {
         return _.filter(array, _.identity);
       };
  • -
  • +
  • - +

    Internal implementation of a recursive flatten function.

    -
      var flatten = function(input, shallow, output) {
    +            
      var flatten = function(input, shallow, strict, output) {
         if (shallow && _.every(input, _.isArray)) {
           return concat.apply(output, input);
         }
    -    each(input, function(value) {
    -      if (_.isArray(value) || _.isArguments(value)) {
    -        shallow ? push.apply(output, value) : flatten(value, shallow, output);
    +    for (var i = 0, length = input.length; i < length; i++) {
    +      var value = input[i];
    +      if (!_.isArray(value) && !_.isArguments(value)) {
    +        if (!strict) output.push(value);
    +      } else if (shallow) {
    +        push.apply(output, value);
           } else {
    -        output.push(value);
    +        flatten(value, shallow, strict, output);
           }
    -    });
    +    }
         return output;
       };
  • -
  • +
  • - +

    Flatten out an array, either recursively (by default), or just one level.

    -
      _.flatten = function(array, shallow) {
    -    return flatten(array, shallow, []);
    +            
      _.flatten = function(array, shallow) {
    +    return flatten(array, shallow, false, []);
       };
  • -
  • +
  • - +

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

    -
      _.without = function(array) {
    +            
      _.without = function(array) {
         return _.difference(array, slice.call(arguments, 1));
       };
  • -
  • -
    - -
    - -
    -

    Split an array into two arrays: one whose elements all satisfy the given -predicate, and one whose elements all do not satisfy the predicate.

    - -
    - -
      _.partition = function(array, predicate) {
    -    var pass = [], fail = [];
    -    each(array, function(elem) {
    -      (predicate(elem) ? pass : fail).push(elem);
    -    });
    -    return [pass, fail];
    -  };
    - -
  • - - -
  • +
  • @@ -1123,22 +1147,32 @@

    Array Functions

    -
      _.uniq = _.unique = function(array, isSorted, iterator, context) {
    -    if (_.isFunction(isSorted)) {
    -      context = iterator;
    -      iterator = isSorted;
    +            
      _.uniq = _.unique = function(array, isSorted, iteratee, context) {
    +    if (array == null) return [];
    +    if (!_.isBoolean(isSorted)) {
    +      context = iteratee;
    +      iteratee = isSorted;
           isSorted = false;
         }
    -    var initial = iterator ? _.map(array, iterator, context) : array;
    -    var results = [];
    +    if (iteratee != null) iteratee = _.iteratee(iteratee, context);
    +    var result = [];
         var seen = [];
    -    each(initial, function(value, index) {
    -      if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
    -        seen.push(value);
    -        results.push(array[index]);
    +    for (var i = 0, length = array.length; i < length; i++) {
    +      var value = array[i];
    +      if (isSorted) {
    +        if (!i || seen !== value) result.push(value);
    +        seen = value;
    +      } else if (iteratee) {
    +        var computed = iteratee(value, i, array);
    +        if (_.indexOf(seen, computed) < 0) {
    +          seen.push(computed);
    +          result.push(value);
    +        }
    +      } else if (_.indexOf(result, value) < 0) {
    +        result.push(value);
           }
    -    });
    -    return results;
    +    }
    +    return result;
       };
  • @@ -1155,8 +1189,8 @@

    Array Functions

    -
      _.union = function() {
    -    return _.uniq(_.flatten(arguments, true));
    +            
      _.union = function() {
    +    return _.uniq(flatten(arguments, true, true, []));
       };
    @@ -1173,13 +1207,19 @@

    Array Functions

    -
      _.intersection = function(array) {
    -    var rest = slice.call(arguments, 1);
    -    return _.filter(_.uniq(array), function(item) {
    -      return _.every(rest, function(other) {
    -        return _.contains(other, item);
    -      });
    -    });
    +            
      _.intersection = function(array) {
    +    if (array == null) return [];
    +    var result = [];
    +    var argsLength = arguments.length;
    +    for (var i = 0, length = array.length; i < length; i++) {
    +      var item = array[i];
    +      if (_.contains(result, item)) continue;
    +      for (var j = 1; j < argsLength; j++) {
    +        if (!_.contains(arguments[j], item)) break;
    +      }
    +      if (j === argsLength) result.push(item);
    +    }
    +    return result;
       };
    @@ -1196,9 +1236,11 @@

    Array Functions

    -
      _.difference = function(array) {
    -    var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
    -    return _.filter(array, function(value){ return !_.contains(rest, value); });
    +            
      _.difference = function(array) {
    +    var rest = flatten(slice.call(arguments, 1), true, true, []);
    +    return _.filter(array, function(value){
    +      return !_.contains(rest, value);
    +    });
       };
    @@ -1215,11 +1257,12 @@

    Array Functions

    -
      _.zip = function() {
    -    var length = _.max(_.pluck(arguments, 'length').concat(0));
    -    var results = new Array(length);
    +            
      _.zip = function(array) {
    +    if (array == null) return [];
    +    var length = _.max(arguments, 'length').length;
    +    var results = Array(length);
         for (var i = 0; i < length; i++) {
    -      results[i] = _.pluck(arguments, '' + i);
    +      results[i] = _.pluck(arguments, i);
         }
         return results;
       };
    @@ -1239,7 +1282,7 @@

    Array Functions

    -
      _.object = function(list, values) {
    +            
      _.object = function(list, values) {
         if (list == null) return {};
         var result = {};
         for (var i = 0, length = list.length; i < length; i++) {
    @@ -1261,63 +1304,46 @@ 

    Array Functions

    -

    If the browser doesn’t supply us with indexOf (I’m looking at you, MSIE), -we need this function. Return the position of the first occurrence of an -item in an array, or -1 if the item is not included in the array. -Delegates to ECMAScript 5‘s native indexOf if available. +

    Return the position of the first occurrence of an item in an array, +or -1 if the item is not included in the array. If the array is large and already in sort order, pass true for isSorted to use binary search.

    -
      _.indexOf = function(array, item, isSorted) {
    +            
      _.indexOf = function(array, item, isSorted) {
         if (array == null) return -1;
         var i = 0, length = array.length;
         if (isSorted) {
           if (typeof isSorted == 'number') {
    -        i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
    +        i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
           } else {
             i = _.sortedIndex(array, item);
             return array[i] === item ? i : -1;
           }
         }
    -    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
         for (; i < length; i++) if (array[i] === item) return i;
         return -1;
    -  };
    - - - - -
  • -
    - -
    - -
    -

    Delegates to ECMAScript 5‘s native lastIndexOf if available.

    + }; -
    - -
      _.lastIndexOf = function(array, item, from) {
    +  _.lastIndexOf = function(array, item, from) {
         if (array == null) return -1;
    -    var hasIndex = from != null;
    -    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
    -      return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
    +    var idx = array.length;
    +    if (typeof from == 'number') {
    +      idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
         }
    -    var i = (hasIndex ? from : array.length);
    -    while (i--) if (array[i] === item) return i;
    +    while (--idx >= 0) if (array[idx] === item) return idx;
         return -1;
       };
  • -
  • +
  • - +

    Generate an integer Array containing an arithmetic progression. A port of the native Python range() function. See @@ -1325,20 +1351,18 @@

    Array Functions

    -
      _.range = function(start, stop, step) {
    +            
      _.range = function(start, stop, step) {
         if (arguments.length <= 1) {
           stop = start || 0;
           start = 0;
         }
    -    step = arguments[2] || 1;
    +    step = step || 1;
     
         var length = Math.max(Math.ceil((stop - start) / step), 0);
    -    var idx = 0;
    -    var range = new Array(length);
    +    var range = Array(length);
     
    -    while(idx < length) {
    -      range[idx++] = start;
    -      start += step;
    +    for (var idx = 0; idx < length; idx++, start += step) {
    +      range[idx] = start;
         }
     
         return range;
    @@ -1347,11 +1371,11 @@ 

    Array Functions

  • -
  • +
  • - +

    Function (ahem) Functions

    @@ -1360,11 +1384,11 @@

    Function (ahem) Functions

  • -
  • +
  • - +
    @@ -1372,26 +1396,26 @@

    Function (ahem) Functions

  • -
  • +
  • - +

    Reusable constructor function for prototype setting.

    -
      var ctor = function(){};
    +
      var Ctor = function(){};
  • -
  • +
  • - +

    Create a function bound to a given object (assigning this, and arguments, optionally). Delegates to ECMAScript 5‘s native Function.bind if @@ -1399,30 +1423,31 @@

    Function (ahem) Functions

    -
      _.bind = function(func, context) {
    +            
      _.bind = function(func, context) {
         var args, bound;
         if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
    -    if (!_.isFunction(func)) throw new TypeError;
    +    if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
         args = slice.call(arguments, 2);
    -    return bound = function() {
    +    bound = function() {
           if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
    -      ctor.prototype = func.prototype;
    -      var self = new ctor;
    -      ctor.prototype = null;
    +      Ctor.prototype = func.prototype;
    +      var self = new Ctor;
    +      Ctor.prototype = null;
           var result = func.apply(self, args.concat(slice.call(arguments)));
    -      if (Object(result) === result) return result;
    +      if (_.isObject(result)) return result;
           return self;
         };
    +    return bound;
       };
  • -
  • +
  • - +

    Partially apply a function by creating a version that has had some of its arguments pre-filled, without changing its dynamic this context. _ acts @@ -1430,9 +1455,9 @@

    Function (ahem) Functions

    -
      _.partial = function(func) {
    +            
      _.partial = function(func) {
         var boundArgs = slice.call(arguments, 1);
    -    return function() {
    +    return function() {
           var position = 0;
           var args = boundArgs.slice();
           for (var i = 0, length = args.length; i < length; i++) {
    @@ -1446,11 +1471,11 @@ 

    Function (ahem) Functions

  • -
  • +
  • - +

    Bind a number of an object’s methods to that object. Remaining arguments are the method names to be bound. Useful for ensuring that all callbacks @@ -1458,80 +1483,87 @@

    Function (ahem) Functions

    -
      _.bindAll = function(obj) {
    -    var funcs = slice.call(arguments, 1);
    -    if (funcs.length === 0) throw new Error('bindAll must be passed function names');
    -    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
    +            
      _.bindAll = function(obj) {
    +    var i, length = arguments.length, key;
    +    if (length <= 1) throw new Error('bindAll must be passed function names');
    +    for (i = 1; i < length; i++) {
    +      key = arguments[i];
    +      obj[key] = _.bind(obj[key], obj);
    +    }
         return obj;
       };
  • -
  • +
  • - +

    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 _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
    +            
      _.memoize = function(func, hasher) {
    +    var memoize = function(key) {
    +      var cache = memoize.cache;
    +      var address = hasher ? hasher.apply(this, arguments) : key;
    +      if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
    +      return cache[address];
         };
    +    memoize.cache = {};
    +    return memoize;
       };
  • -
  • +
  • - +

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

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

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

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

    Returns a function, that, when invoked, will only be triggered at most once during a given window of time. Normally, the throttled function will run @@ -1541,29 +1573,29 @@

    Function (ahem) Functions

    -
      _.throttle = function(func, wait, options) {
    +            
      _.throttle = function(func, wait, options) {
         var context, args, result;
         var timeout = null;
         var previous = 0;
    -    options || (options = {});
    -    var later = function() {
    +    if (!options) options = {};
    +    var later = function() {
           previous = options.leading === false ? 0 : _.now();
           timeout = null;
           result = func.apply(context, args);
    -      context = args = null;
    +      if (!timeout) context = args = null;
         };
    -    return function() {
    +    return function() {
           var now = _.now();
           if (!previous && options.leading === false) previous = now;
           var remaining = wait - (now - previous);
           context = this;
           args = arguments;
    -      if (remaining <= 0) {
    +      if (remaining <= 0 || remaining > wait) {
             clearTimeout(timeout);
             timeout = null;
             previous = now;
             result = func.apply(context, args);
    -        context = args = null;
    +        if (!timeout) context = args = null;
           } else if (!timeout && options.trailing !== false) {
             timeout = setTimeout(later, remaining);
           }
    @@ -1574,11 +1606,11 @@ 

    Function (ahem) Functions

  • -
  • +
  • - +

    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 @@ -1587,30 +1619,29 @@

    Function (ahem) Functions

    -
      _.debounce = function(func, wait, immediate) {
    +            
      _.debounce = function(func, wait, immediate) {
         var timeout, args, context, timestamp, result;
     
    -    var later = function() {
    +    var later = function() {
           var last = _.now() - timestamp;
    -      if (last < wait) {
    +
    +      if (last < wait && last > 0) {
             timeout = setTimeout(later, wait - last);
           } else {
             timeout = null;
             if (!immediate) {
               result = func.apply(context, args);
    -          context = args = null;
    +          if (!timeout) context = args = null;
             }
           }
         };
     
    -    return function() {
    +    return function() {
           context = this;
           args = arguments;
           timestamp = _.now();
           var callNow = immediate && !timeout;
    -      if (!timeout) {
    -        timeout = setTimeout(later, wait);
    -      }
    +      if (!timeout) timeout = setTimeout(later, wait);
           if (callNow) {
             result = func.apply(context, args);
             context = args = null;
    @@ -1623,25 +1654,38 @@ 

    Function (ahem) Functions

  • +
  • +
    + +
    + +
    +

    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 _.partial(wrapper, func);
    +  };
    + +
  • + +
  • -

    Returns a function that will be executed at most one time, no matter how -often you call it. Useful for lazy initialization.

    +

    Returns a negated version of the passed-in predicate.

    -
      _.once = function(func) {
    -    var ran = false, memo;
    -    return function() {
    -      if (ran) return memo;
    -      ran = true;
    -      memo = func.apply(this, arguments);
    -      func = null;
    -      return memo;
    +            
      _.negate = function(predicate) {
    +    return function() {
    +      return !predicate.apply(this, arguments);
         };
       };
    @@ -1654,14 +1698,20 @@

    Function (ahem) Functions

    -

    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.

    +

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

    -
      _.wrap = function(func, wrapper) {
    -    return _.partial(wrapper, func);
    +            
      _.compose = function() {
    +    var args = arguments;
    +    var start = args.length - 1;
    +    return function() {
    +      var i = start;
    +      var result = args[start].apply(this, arguments);
    +      while (i--) result = args[i].call(this, result);
    +      return result;
    +    };
       };
  • @@ -1673,19 +1723,15 @@

    Function (ahem) Functions

    -

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

    +

    Returns a function that will only be executed after being called N times.

    -
      _.compose = function() {
    -    var funcs = arguments;
    -    return function() {
    -      var args = arguments;
    -      for (var i = funcs.length - 1; i >= 0; i--) {
    -        args = [funcs[i].apply(this, args)];
    +            
      _.after = function(times, func) {
    +    return function() {
    +      if (--times < 1) {
    +        return func.apply(this, arguments);
           }
    -      return args[0];
         };
       };
    @@ -1698,15 +1744,18 @@

    Function (ahem) Functions

    -

    Returns a function that will only be executed after being called N times.

    +

    Returns a function that will only be executed before being called N times.

    -
      _.after = function(times, func) {
    -    return function() {
    -      if (--times < 1) {
    -        return func.apply(this, arguments);
    +            
      _.before = function(times, func) {
    +    var memo;
    +    return function() {
    +      if (--times > 0) {
    +        memo = func.apply(this, arguments);
           }
    +      else func = null;
    +      return memo;
         };
       };
    @@ -1719,10 +1768,13 @@

    Function (ahem) Functions

    -

    Object Functions

    +

    Returns a function that will be executed at most one time, no matter how +often you call it. Useful for lazy initialization.

    +
      _.once = _.partial(_.before, 2);
    + @@ -1732,7 +1784,8 @@

    Object Functions

    - +

    Object Functions

    +
    @@ -1744,12 +1797,24 @@

    Object Functions

    + +
    + + + + +
  • +
    + +
    + +

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

    -
      _.keys = function(obj) {
    +            
      _.keys = function(obj) {
         if (!_.isObject(obj)) return [];
         if (nativeKeys) return nativeKeys(obj);
         var keys = [];
    @@ -1760,20 +1825,20 @@ 

    Object Functions

  • -
  • +
  • - +

    Retrieve the values of an object’s properties.

    -
      _.values = function(obj) {
    +            
      _.values = function(obj) {
         var keys = _.keys(obj);
         var length = keys.length;
    -    var values = new Array(length);
    +    var values = Array(length);
         for (var i = 0; i < length; i++) {
           values[i] = obj[keys[i]];
         }
    @@ -1783,20 +1848,20 @@ 

    Object Functions

  • -
  • +
  • - +

    Convert an object into a list of [key, value] pairs.

    -
      _.pairs = function(obj) {
    +            
      _.pairs = function(obj) {
         var keys = _.keys(obj);
         var length = keys.length;
    -    var pairs = new Array(length);
    +    var pairs = Array(length);
         for (var i = 0; i < length; i++) {
           pairs[i] = [keys[i], obj[keys[i]]];
         }
    @@ -1806,17 +1871,17 @@ 

    Object Functions

  • -
  • +
  • - +

    Invert the keys and values of an object. The values must be serializable.

    -
      _.invert = function(obj) {
    +            
      _.invert = function(obj) {
         var result = {};
         var keys = _.keys(obj);
         for (var i = 0, length = keys.length; i < length; i++) {
    @@ -1828,18 +1893,18 @@ 

    Object Functions

  • -
  • +
  • - +

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

    -
      _.functions = _.methods = function(obj) {
    +            
      _.functions = _.methods = function(obj) {
         var names = [];
         for (var key in obj) {
           if (_.isFunction(obj[key])) names.push(key);
    @@ -1850,109 +1915,126 @@ 

    Object Functions

  • -
  • +
  • - +

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

    -
      _.extend = function(obj) {
    -    each(slice.call(arguments, 1), function(source) {
    -      if (source) {
    -        for (var prop in source) {
    -          obj[prop] = source[prop];
    +            
      _.extend = function(obj) {
    +    if (!_.isObject(obj)) return obj;
    +    var source, prop;
    +    for (var i = 1, length = arguments.length; i < length; i++) {
    +      source = arguments[i];
    +      for (prop in source) {
    +        if (hasOwnProperty.call(source, prop)) {
    +            obj[prop] = source[prop];
             }
           }
    -    });
    +    }
         return obj;
       };
  • -
  • +
  • - +

    Return a copy of the object only containing the whitelisted properties.

    -
      _.pick = function(obj) {
    -    var copy = {};
    -    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
    -    each(keys, function(key) {
    -      if (key in obj) copy[key] = obj[key];
    -    });
    -    return copy;
    +            
      _.pick = function(obj, iteratee, context) {
    +    var result = {}, key;
    +    if (obj == null) return result;
    +    if (_.isFunction(iteratee)) {
    +      iteratee = createCallback(iteratee, context);
    +      for (key in obj) {
    +        var value = obj[key];
    +        if (iteratee(value, key, obj)) result[key] = value;
    +      }
    +    } else {
    +      var keys = concat.apply([], slice.call(arguments, 1));
    +      obj = new Object(obj);
    +      for (var i = 0, length = keys.length; i < length; i++) {
    +        key = keys[i];
    +        if (key in obj) result[key] = obj[key];
    +      }
    +    }
    +    return result;
       };
  • -
  • +
  • - +

    Return a copy of the object without the blacklisted properties.

    -
      _.omit = function(obj) {
    -    var copy = {};
    -    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
    -    for (var key in obj) {
    -      if (!_.contains(keys, key)) copy[key] = obj[key];
    +            
      _.omit = function(obj, iteratee, context) {
    +    if (_.isFunction(iteratee)) {
    +      iteratee = _.negate(iteratee);
    +    } else {
    +      var keys = _.map(concat.apply([], slice.call(arguments, 1)), String);
    +      iteratee = function(value, key) {
    +        return !_.contains(keys, key);
    +      };
         }
    -    return copy;
    +    return _.pick(obj, iteratee, context);
       };
  • -
  • +
  • - +

    Fill in a given object with default properties.

    -
      _.defaults = function(obj) {
    -    each(slice.call(arguments, 1), function(source) {
    -      if (source) {
    -        for (var prop in source) {
    -          if (obj[prop] === void 0) obj[prop] = source[prop];
    -        }
    +            
      _.defaults = function(obj) {
    +    if (!_.isObject(obj)) return obj;
    +    for (var i = 1, length = arguments.length; i < length; i++) {
    +      var source = arguments[i];
    +      for (var prop in source) {
    +        if (obj[prop] === void 0) obj[prop] = source[prop];
           }
    -    });
    +    }
         return obj;
       };
  • -
  • +
  • - +

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

    -
      _.clone = function(obj) {
    +            
      _.clone = function(obj) {
         if (!_.isObject(obj)) return obj;
         return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
       };
    @@ -1960,11 +2042,11 @@

    Object Functions

  • -
  • +
  • - +

    Invokes interceptor with the obj, and then returns obj. The primary purpose of this method is to “tap into” a method chain, in @@ -1972,7 +2054,7 @@

    Object Functions

    -
      _.tap = function(obj, interceptor) {
    +            
      _.tap = function(obj, interceptor) {
         interceptor(obj);
         return obj;
       };
    @@ -1980,42 +2062,42 @@

    Object Functions

  • -
  • +
  • - +

    Internal recursive comparison function for isEqual.

    -
      var eq = function(a, b, aStack, bStack) {
    +
      var eq = function(a, b, aStack, bStack) {
  • -
  • +
  • - +

    Identical objects are equal. 0 === -0, but they aren’t identical. See the Harmony egal proposal.

    -
        if (a === b) return a !== 0 || 1 / a == 1 / b;
    +
        if (a === b) return a !== 0 || 1 / a === 1 / b;
  • -
  • +
  • - +

    A strict comparison is necessary because null == undefined.

    @@ -2026,11 +2108,11 @@

    Object Functions

  • -
  • +
  • - +

    Unwrap any wrapped objects.

    @@ -2042,51 +2124,34 @@

    Object Functions

  • -
  • +
  • - +

    Compare [[Class]] names.

        var className = toString.call(a);
    -    if (className != toString.call(b)) return false;
    +    if (className !== toString.call(b)) return false;
         switch (className) {
  • -
  • -
    - -
    - -
    -

    Strings, numbers, dates, and booleans are compared by value.

    - -
    - -
          case '[object String]':
    - -
  • - -
  • -

    Primitives and their corresponding object wrappers are equivalent; thus, "5" is -equivalent to new String("5").

    +

    Strings, numbers, regular expressions, dates, and booleans are compared by value.

    -
            return a == String(b);
    -      case '[object Number]':
    +
          case '[object RegExp]':
  • @@ -2097,14 +2162,11 @@

    Object Functions

    -

    NaNs are equivalent, but non-reflexive. An egal comparison is performed for -other numeric values.

    +

    RegExps are coerced to strings for comparison (Note: ‘’ + /a/i === ‘/a/i’)

    -
            return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
    -      case '[object Date]':
    -      case '[object Boolean]':
    +
          case '[object String]':
    @@ -2115,13 +2177,13 @@

    Object Functions

    -

    Coerce dates and booleans to numeric primitive values. Dates are compared by their -millisecond representations. Note that invalid dates with millisecond representations -of NaN are not equivalent.

    +

    Primitives and their corresponding object wrappers are equivalent; thus, "5" is +equivalent to new String("5").

    -
            return +a == +b;
    +
            return '' + a === '' + b;
    +      case '[object Number]':
    @@ -2132,17 +2194,12 @@

    Object Functions

    -

    RegExps are compared by their source patterns and flags.

    +

    NaNs are equivalent, but non-reflexive. +Object(NaN) is equivalent to NaN

    -
          case '[object RegExp]':
    -        return a.source == b.source &&
    -               a.global == b.global &&
    -               a.multiline == b.multiline &&
    -               a.ignoreCase == b.ignoreCase;
    -    }
    -    if (typeof a != 'object' || typeof b != 'object') return false;
    +
            if (+a !== +a) return +b !== +b;
    @@ -2153,13 +2210,13 @@

    Object Functions

    -

    Assume equality for cyclic structures. The algorithm for detecting cyclic -structures is adapted from ES 5.1 section 15.12.3, abstract operation JO.

    +

    An egal comparison is performed for other numeric values.

    -
        var length = aStack.length;
    -    while (length--) {
    +
            return +a === 0 ? 1 / +a === 1 / b : +a === +b;
    +      case '[object Date]':
    +      case '[object Boolean]':
    @@ -2170,13 +2227,15 @@

    Object Functions

    -

    Linear search. Performance is inversely proportional to the number of -unique nested structures.

    +

    Coerce dates and booleans to numeric primitive values. Dates are compared by their +millisecond representations. Note that invalid dates with millisecond representations +of NaN are not equivalent.

    -
          if (aStack[length] == a) return bStack[length] == b;
    -    }
    +
            return +a === +b;
    +    }
    +    if (typeof a != 'object' || typeof b != 'object') return false;
    @@ -2187,17 +2246,13 @@

    Object Functions

    -

    Objects with different constructors are not equivalent, but Objects -from different frames are.

    +

    Assume equality for cyclic structures. The algorithm for detecting cyclic +structures is adapted from ES 5.1 section 15.12.3, abstract operation JO.

    -
        var aCtor = a.constructor, bCtor = b.constructor;
    -    if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
    -                             _.isFunction(bCtor) && (bCtor instanceof bCtor))
    -                        && ('constructor' in a && 'constructor' in b)) {
    -      return false;
    -    }
    +
        var length = aStack.length;
    +    while (length--) {
    @@ -2208,13 +2263,13 @@

    Object Functions

    -

    Add the first object to the stack of traversed objects.

    +

    Linear search. Performance is inversely proportional to the number of +unique nested structures.

    -
        aStack.push(a);
    -    bStack.push(b);
    -    var size = 0, result = true;
    +
          if (aStack[length] === a) return bStack[length] === b;
    +    }
    @@ -2225,11 +2280,14 @@

    Object Functions

    -

    Recursively compare objects and arrays.

    +

    Objects with different constructors are not equivalent, but Objects +from different frames are.

    -
        if (className == '[object Array]') {
    +
        var aCtor = a.constructor, bCtor = b.constructor;
    +    if (
    +      aCtor !== bCtor &&
    @@ -2240,13 +2298,16 @@

    Object Functions

    -

    Compare array lengths to determine if a deep comparison is necessary.

    +

    Handle Object.create(x) cases

    -
          size = a.length;
    -      result = size == b.length;
    -      if (result) {
    +
          'constructor' in a && 'constructor' in b &&
    +      !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
    +        _.isFunction(bCtor) && bCtor instanceof bCtor)
    +    ) {
    +      return false;
    +    }
    @@ -2257,15 +2318,13 @@

    Object Functions

    -

    Deep compare the contents, ignoring non-numeric properties.

    +

    Add the first object to the stack of traversed objects.

    -
            while (size--) {
    -          if (!(result = eq(a[size], b[size], aStack, bStack))) break;
    -        }
    -      }
    -    } else {
    +
        aStack.push(a);
    +    bStack.push(b);
    +    var size, result;
    @@ -2276,12 +2335,11 @@

    Object Functions

    -

    Deep compare objects.

    +

    Recursively compare objects and arrays.

    -
          for (var key in a) {
    -        if (_.has(a, key)) {
    +
        if (className === '[object Array]') {
    @@ -2292,11 +2350,13 @@

    Object Functions

    -

    Count the expected number of properties.

    +

    Compare array lengths to determine if a deep comparison is necessary.

    -
              size++;
    +
          size = a.length;
    +      result = size === b.length;
    +      if (result) {
    @@ -2307,13 +2367,15 @@

    Object Functions

    -

    Deep compare each member.

    +

    Deep compare the contents, ignoring non-numeric properties.

    -
              if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
    +            
            while (size--) {
    +          if (!(result = eq(a[size], b[size], aStack, bStack))) break;
             }
    -      }
    + } + } else {
    @@ -2324,26 +2386,57 @@

    Object Functions

    -

    Ensure that both objects contain the same number of properties.

    +

    Deep compare objects.

    -
          if (result) {
    -        for (key in b) {
    -          if (_.has(b, key) && !(size--)) break;
    +            
          var keys = _.keys(a), key;
    +      size = keys.length;
    + + + + +
  • +
    + +
    + +
    +

    Ensure that both objects contain the same number of properties before comparing deep equality.

    + +
    + +
          result = _.keys(b).length === size;
    +      if (result) {
    +        while (size--) {
    + +
  • + + +
  • +
    + +
    + +
    +

    Deep compare each member

    + +
    + +
              key = keys[size];
    +          if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
             }
    -        result = !size;
           }
         }
  • -
  • +
  • - +

    Remove the first object from the stack of traversed objects.

    @@ -2357,37 +2450,37 @@

    Object Functions

  • -
  • +
  • - +

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

    -
      _.isEqual = function(a, b) {
    +            
      _.isEqual = function(a, b) {
         return eq(a, b, [], []);
       };
  • -
  • +
  • - +

    Is a given array, string, or object empty? An “empty” object has no enumerable own-properties.

    -
      _.isEmpty = function(obj) {
    +            
      _.isEmpty = function(obj) {
         if (obj == null) return true;
    -    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
    +    if (_.isArray(obj) || _.isString(obj) || _.isArguments(obj)) return obj.length === 0;
         for (var key in obj) if (_.has(obj, key)) return false;
         return true;
       };
    @@ -2395,82 +2488,83 @@

    Object Functions

  • -
  • +
  • - +

    Is a given value a DOM element?

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

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

    -
      _.isArray = nativeIsArray || function(obj) {
    -    return toString.call(obj) == '[object Array]';
    +            
      _.isArray = nativeIsArray || function(obj) {
    +    return toString.call(obj) === '[object Array]';
       };
  • -
  • +
  • - +

    Is a given variable an object?

    -
      _.isObject = function(obj) {
    -    return obj === Object(obj);
    +            
      _.isObject = function(obj) {
    +    var type = typeof obj;
    +    return type === 'function' || type === 'object' && !!obj;
       };
  • -
  • +
  • - +

    Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.

    -
      each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
    -    _['is' + name] = function(obj) {
    -      return toString.call(obj) == '[object ' + name + ']';
    +            
      _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
    +    _['is' + name] = function(obj) {
    +      return toString.call(obj) === '[object ' + name + ']';
         };
       });
  • -
  • +
  • - +

    Define a fallback version of the method in browsers (ahem, IE), where there isn’t any inspectable “Arguments” type.

    @@ -2478,141 +2572,141 @@

    Object Functions

      if (!_.isArguments(arguments)) {
    -    _.isArguments = function(obj) {
    -      return !!(obj && _.has(obj, 'callee'));
    +    _.isArguments = function(obj) {
    +      return _.has(obj, 'callee');
         };
       }
  • -
  • +
  • - +
    -

    Optimize isFunction if appropriate.

    +

    Optimize isFunction if appropriate. Work around an IE 11 bug.

    -
      if (typeof (/./) !== 'function') {
    -    _.isFunction = function(obj) {
    -      return typeof obj === 'function';
    +            
      if (typeof /./ !== 'function') {
    +    _.isFunction = function(obj) {
    +      return typeof obj == 'function' || false;
         };
       }
  • -
  • +
  • - +

    Is a given object a finite number?

    -
      _.isFinite = function(obj) {
    +            
      _.isFinite = function(obj) {
         return isFinite(obj) && !isNaN(parseFloat(obj));
       };
  • -
  • +
  • - +

    Is the given value NaN? (NaN is the only number which does not equal itself).

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

    Is a given value a boolean?

    -
      _.isBoolean = function(obj) {
    -    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
    +            
      _.isBoolean = function(obj) {
    +    return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
       };
  • -
  • +
  • - +

    Is a given value equal to null?

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

    Is a given variable undefined?

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

    Shortcut function for checking if an object has a given property directly on itself (in other words, not on a prototype).

    -
      _.has = function(obj, key) {
    -    return hasOwnProperty.call(obj, key);
    +            
      _.has = function(obj, key) {
    +    return obj != null && hasOwnProperty.call(obj, key);
       };
  • -
  • +
  • - +

    Utility Functions

    @@ -2621,11 +2715,11 @@

    Utility Functions

  • -
  • +
  • - +
    @@ -2633,18 +2727,18 @@

    Utility Functions

  • -
  • +
  • - +

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

    -
      _.noConflict = function() {
    +            
      _.noConflict = function() {
         root._ = previousUnderscore;
         return this;
       };
    @@ -2652,28 +2746,30 @@

    Utility Functions

  • -
  • +
  • - +
    -

    Keep the identity function around for default iterators.

    +

    Keep the identity function around for default iteratees.

    -
      _.identity = function(value) {
    +            
      _.identity = function(value) {
         return value;
       };
     
    -  _.constant = function(value) {
    -    return function () {
    +  _.constant = function(value) {
    +    return function() {
           return value;
         };
       };
     
    -  _.property = function(key) {
    -    return function(obj) {
    +  _.noop = function(){};
    +
    +  _.property = function(key) {
    +    return function(obj) {
           return obj[key];
         };
       };
    @@ -2681,60 +2777,63 @@

    Utility Functions

  • -
  • +
  • - +

    Returns a predicate for checking whether an object has a given set of key:value pairs.

    -
      _.matches = function(attrs) {
    -    return function(obj) {
    -      if (obj === attrs) return true; //avoid comparing an object to itself.
    -      for (var key in attrs) {
    -        if (attrs[key] !== obj[key])
    -          return false;
    +            
      _.matches = function(attrs) {
    +    var pairs = _.pairs(attrs), length = pairs.length;
    +    return function(obj) {
    +      if (obj == null) return !length;
    +      obj = new Object(obj);
    +      for (var i = 0; i < length; i++) {
    +        var pair = pairs[i], key = pair[0];
    +        if (pair[1] !== obj[key] || !(key in obj)) return false;
           }
           return true;
    -    }
    +    };
       };
  • -
  • +
  • - +

    Run a function n times.

    -
      _.times = function(n, iterator, context) {
    +            
      _.times = function(n, iteratee, context) {
         var accum = Array(Math.max(0, n));
    -    for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
    +    iteratee = createCallback(iteratee, context, 1);
    +    for (var i = 0; i < n; i++) accum[i] = iteratee(i);
         return accum;
       };
  • -
  • +
  • - +

    Return a random integer between min and max (inclusive).

    -
      _.random = function(min, max) {
    +            
      _.random = function(min, max) {
         if (max == null) {
           max = min;
           min = 0;
    @@ -2745,134 +2844,113 @@ 

    Utility Functions

  • -
  • +
  • - +

    A (possibly faster) way to get the current timestamp as an integer.

    -
      _.now = Date.now || function() { return new Date().getTime(); };
    +
      _.now = Date.now || function() {
    +    return new Date().getTime();
    +  };
  • -
  • +
  • - +

    List of HTML entities for escaping.

    -
      var entityMap = {
    -    escape: {
    -      '&': '&amp;',
    -      '<': '&lt;',
    -      '>': '&gt;',
    -      '"': '&quot;',
    -      "'": '&#x27;'
    -    }
    +            
      var escapeMap = {
    +    '&': '&amp;',
    +    '<': '&lt;',
    +    '>': '&gt;',
    +    '"': '&quot;',
    +    "'": '&#x27;',
    +    '`': '&#x60;'
       };
    -  entityMap.unescape = _.invert(entityMap.escape);
    + var unescapeMap = _.invert(escapeMap);
  • -
  • +
  • - +
    -

    Regexes containing the keys and values listed immediately above.

    +

    Functions for escaping and unescaping strings to/from HTML interpolation.

    -
      var entityRegexes = {
    -    escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
    -    unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
    -  };
    +
      var createEscaper = function(map) {
    +    var escaper = function(match) {
    +      return map[match];
    +    };
  • -
  • +
  • - +
    -

    Functions for escaping and unescaping strings to/from HTML interpolation.

    +

    Regexes for identifying a key that needs to be escaped

    -
      _.each(['escape', 'unescape'], function(method) {
    -    _[method] = function(string) {
    -      if (string == null) return '';
    -      return ('' + string).replace(entityRegexes[method], function(match) {
    -        return entityMap[method][match];
    -      });
    +            
        var source = '(?:' + _.keys(map).join('|') + ')';
    +    var testRegexp = RegExp(source);
    +    var replaceRegexp = RegExp(source, 'g');
    +    return function(string) {
    +      string = string == null ? '' : '' + string;
    +      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
         };
    -  });
    + }; + _.escape = createEscaper(escapeMap); + _.unescape = createEscaper(unescapeMap);
  • -
  • +
  • - +

    If the value of the named property is a function then invoke it with the object as context; otherwise, return it.

    -
      _.result = function(object, property) {
    +            
      _.result = function(object, property) {
         if (object == null) return void 0;
         var value = object[property];
    -    return _.isFunction(value) ? value.call(object) : value;
    +    return _.isFunction(value) ? object[property]() : value;
       };
  • -
  • -
    - -
    - -
    -

    Add your own custom functions to the Underscore object.

    - -
    - -
      _.mixin = function(obj) {
    -    each(_.functions(obj), function(name) {
    -      var func = _[name] = obj[name];
    -      _.prototype[name] = function() {
    -        var args = [this._wrapped];
    -        push.apply(args, arguments);
    -        return result.call(this, func.apply(_, args));
    -      };
    -    });
    -  };
    - -
  • - - -
  • +
  • - +

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

    @@ -2880,7 +2958,7 @@

    Utility Functions

      var idCounter = 0;
    -  _.uniqueId = function(prefix) {
    +  _.uniqueId = function(prefix) {
         var id = ++idCounter + '';
         return prefix ? prefix + id : id;
       };
    @@ -2888,11 +2966,11 @@

    Utility Functions

  • -
  • +
  • - +

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

    @@ -2908,11 +2986,11 @@

    Utility Functions

  • -
  • +
  • - +

    When customizing templateSettings, if you don’t want to define an interpolation, evaluation or escaping regex, we need one that is @@ -2925,11 +3003,11 @@

    Utility Functions

  • -
  • +
  • - +

    Certain characters need to be escaped so that they can be put into a string literal.

    @@ -2941,46 +3019,50 @@

    Utility Functions

    '\\': '\\', '\r': 'r', '\n': 'n', - '\t': 't', '\u2028': 'u2028', '\u2029': 'u2029' }; - var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
  • + var escaper = /\\|'|\r|\n|\u2028|\u2029/g; + + var escapeChar = function(match) { + return '\\' + escapes[match]; + };
    -
  • +
  • - +

    JavaScript micro-templating, similar to John Resig’s implementation. Underscore templating handles arbitrary delimiters, preserves whitespace, -and correctly escapes quotes within interpolated code.

    +and correctly escapes quotes within interpolated code. +NB: oldSettings only exists for backwards compatibility.

    -
      _.template = function(text, data, settings) {
    -    var render;
    +            
      _.template = function(text, settings, oldSettings) {
    +    if (!settings && oldSettings) settings = oldSettings;
         settings = _.defaults({}, settings, _.templateSettings);
  • -
  • +
  • - +

    Combine delimiters into one regular expression via alternation.

    -
        var matcher = new RegExp([
    +            
        var matcher = RegExp([
           (settings.escape || noMatch).source,
           (settings.interpolate || noMatch).source,
           (settings.evaluate || noMatch).source
    @@ -2989,11 +3071,11 @@ 

    Utility Functions

  • -
  • +
  • - +

    Compile the template source, escaping string literals appropriately.

    @@ -3001,32 +3083,43 @@

    Utility Functions

        var index = 0;
         var source = "__p+='";
    -    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
    -      source += text.slice(index, offset)
    -        .replace(escaper, function(match) { return '\\' + escapes[match]; });
    +    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
    +      source += text.slice(index, offset).replace(escaper, escapeChar);
    +      index = offset + match.length;
     
           if (escape) {
             source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
    -      }
    -      if (interpolate) {
    +      } else if (interpolate) {
             source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
    -      }
    -      if (evaluate) {
    +      } else if (evaluate) {
             source += "';\n" + evaluate + "\n__p+='";
    -      }
    -      index = offset + match.length;
    -      return match;
    +      }
    + +
  • + + +
  • +
    + +
    + +
    +

    Adobe VMs need the match returned to produce the correct offest.

    + +
    + +
          return match;
         });
         source += "';\n";
  • -
  • +
  • - +

    If a variable is not specified, place data values in local scope.

    @@ -3036,34 +3129,34 @@

    Utility Functions

    source = "var __t,__p='',__j=Array.prototype.join," + "print=function(){__p+=__j.call(arguments,'');};\n" + - source + "return __p;\n"; + source + 'return __p;\n'; try { - render = new Function(settings.variable || 'obj', '_', source); + var render = new Function(settings.variable || 'obj', '_', source); } catch (e) { e.source = source; throw e; } - if (data) return render(data, _); - var template = function(data) { + var template = function(data) { return render.call(this, data, _); };
  • -
  • +
  • - +
    -

    Provide the compiled function source as a convenience for precompilation.

    +

    Provide the compiled source as a convenience for precompilation.

    -
        template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
    +            
        var argument = settings.variable || 'obj';
    +    template.source = 'function(' + argument + '){\n' + source + '}';
     
         return template;
       };
    @@ -3071,28 +3164,30 @@

    Utility Functions

  • -
  • +
  • - +
    -

    Add a “chain” function, which will delegate to the wrapper.

    +

    Add a “chain” function. Start chaining a wrapped Underscore object.

    -
      _.chain = function(obj) {
    -    return _(obj).chain();
    +            
      _.chain = function(obj) {
    +    var instance = _(obj);
    +    instance._chain = true;
    +    return instance;
       };
  • -
  • +
  • - +

    OOP

    @@ -3101,11 +3196,11 @@

    OOP

  • -
  • +
  • - +

    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 @@ -3116,125 +3211,127 @@

    OOP

  • -
  • +
  • - +

    Helper function to continue chaining intermediate results.

    -
      var result = function(obj) {
    +            
      var result = function(obj) {
         return this._chain ? _(obj).chain() : obj;
       };
  • -
  • +
  • - +
    -

    Add all of the Underscore functions to the wrapper object.

    +

    Add your own custom functions to the Underscore object.

    -
      _.mixin(_);
    +
      _.mixin = function(obj) {
    +    _.each(_.functions(obj), function(name) {
    +      var func = _[name] = obj[name];
    +      _.prototype[name] = function() {
    +        var args = [this._wrapped];
    +        push.apply(args, arguments);
    +        return result.call(this, func.apply(_, args));
    +      };
    +    });
    +  };
  • -
  • +
  • - +
    -

    Add all mutator Array functions to the wrapper.

    +

    Add all of the Underscore functions to the wrapper object.

    -
      each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
    -    var method = ArrayProto[name];
    -    _.prototype[name] = function() {
    -      var obj = this._wrapped;
    -      method.apply(obj, arguments);
    -      if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
    -      return result.call(this, obj);
    -    };
    -  });
    +
      _.mixin(_);
  • -
  • +
  • - +
    -

    Add all accessor Array functions to the wrapper.

    +

    Add all mutator Array functions to the wrapper.

    -
      each(['concat', 'join', 'slice'], function(name) {
    +            
      _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
         var method = ArrayProto[name];
    -    _.prototype[name] = function() {
    -      return result.call(this, method.apply(this._wrapped, arguments));
    +    _.prototype[name] = function() {
    +      var obj = this._wrapped;
    +      method.apply(obj, arguments);
    +      if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
    +      return result.call(this, obj);
         };
    -  });
    -
    -  _.extend(_.prototype, {
    + });
  • -
  • +
  • - +
    -

    Start chaining a wrapped Underscore object.

    +

    Add all accessor Array functions to the wrapper.

    -
        chain: function() {
    -      this._chain = true;
    -      return this;
    -    },
    +
      _.each(['concat', 'join', 'slice'], function(name) {
    +    var method = ArrayProto[name];
    +    _.prototype[name] = function() {
    +      return result.call(this, method.apply(this._wrapped, arguments));
    +    };
    +  });
  • -
  • +
  • - +

    Extracts the result from a wrapped and chained object.

    -
        value: function() {
    -      return this._wrapped;
    -    }
    -
    -  });
    +
      _.prototype.value = function() {
    +    return this._wrapped;
    +  };
  • -
  • +
  • - +

    AMD registration happens at the end for compatibility with AMD loaders that may not enforce next-turn semantics on modules. Even though general @@ -3247,11 +3344,11 @@

    OOP

      if (typeof define === 'function' && define.amd) {
    -    define('underscore', [], function() {
    +    define('underscore', [], function() {
           return _;
         });
       }
    -}).call(this);
    +}.call(this));
  • diff --git a/index.html b/index.html index cdab3e4aa..be7e92fc9 100644 --- a/index.html +++ b/index.html @@ -180,7 +180,7 @@