From d137c27447690f21b0c4fc3ec9c04a90e9177a32 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Thu, 4 Oct 2012 14:56:36 -0700 Subject: [PATCH 1/3] add missing word to change log --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index dec084ce8..bbf3e07e3 100644 --- a/index.html +++ b/index.html @@ -1798,7 +1798,7 @@

Change Log

  • "Sparse" arrays are no longer supported in Underscore iteration - functions. Use a for instead (or better yet, an object). + functions. Use a for loop instead (or better yet, an object).
  • The min and max functions may now be called on From df780a72e8f07d2a6d75483e5e64491552388ff0 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Sat, 6 Oct 2012 22:47:51 -0400 Subject: [PATCH 2/3] reverted removal of null checks in collection functions. --- test/arrays.js | 2 ++ test/collections.js | 26 ++++++++++++++++++++++++++ underscore.js | 11 +++++++++++ 3 files changed, 39 insertions(+) diff --git a/test/arrays.js b/test/arrays.js index 1ab33d8f7..a757ced67 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -144,6 +144,7 @@ $(document).ready(function() { equal(_.indexOf(numbers, 2), 1, 'can compute indexOf, even without the native function'); var result = (function(){ return _.indexOf(arguments, 2); })(1, 2, 3); equal(result, 1, 'works on an arguments object'); + equal(_.indexOf(null, 2), -1, 'handles nulls properly'); var numbers = [10, 20, 30, 40, 50], num = 35; var index = _.indexOf(numbers, num, true); @@ -172,6 +173,7 @@ $(document).ready(function() { equal(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element'); var result = (function(){ return _.lastIndexOf(arguments, 1); })(1, 0, 1, 0, 0, 1, 0, 0, 0); equal(result, 5, 'works on an arguments object'); + equal(_.indexOf(null, 2), -1, 'handles nulls properly'); numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; index = _.lastIndexOf(numbers, 2, 2); diff --git a/test/collections.js b/test/collections.js index 095ace1d3..efc5723d4 100644 --- a/test/collections.js +++ b/test/collections.js @@ -25,6 +25,10 @@ $(document).ready(function() { answer = null; _.each([1, 2, 3], function(num, index, arr){ if (_.include(arr, num)) answer = true; }); ok(answer, 'can reference the original collection from inside the iterator'); + + answers = 0; + _.each(null, function(){ ++answers; }); + equal(answers, 0, 'handles a null properly'); }); test('map', function() { @@ -50,6 +54,9 @@ $(document).ready(function() { var ids = _.map(document.images, function(n){ return n.id; }); ok(ids[0] == 'chart_image', 'can use collection methods on HTMLCollections'); + + var ifnull = _.map(null, function(){}); + ok(_.isArray(ifnull) && ifnull.length === 0, 'handles a null properly'); }); test('reduce', function() { @@ -69,6 +76,15 @@ $(document).ready(function() { var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; }); equal(sum, 6, 'default initial value'); + var ifnull; + try { + _.reduce(null, function(){}); + } catch (ex) { + ifnull = ex; + } + ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly'); + + ok(_.reduce(null, function(){}, 138) === 138, 'handles a null (with initial value) properly'); equal(_.reduce([], function(){}, undefined), undefined, 'undefined can be passed as a special case'); raises(function() { _.reduce([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value'); }); @@ -83,9 +99,19 @@ $(document).ready(function() { var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; }); equal(list, 'bazbarfoo', 'default initial value'); + var ifnull; + try { + _.reduceRight(null, function(){}); + } catch (ex) { + ifnull = ex; + } + ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly'); + var sum = _.reduceRight({a: 1, b: 2, c: 3}, function(sum, num){ return sum + num; }); equal(sum, 6, 'default initial value on object'); + ok(_.reduceRight(null, function(){}, 138) === 138, 'handles a null (with initial value) properly'); + equal(_.reduceRight([], function(){}, undefined), undefined, 'undefined can be passed as a special case'); raises(function() { _.reduceRight([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value'); diff --git a/underscore.js b/underscore.js index 2ab97e902..6b4f8b2c0 100644 --- a/underscore.js +++ b/underscore.js @@ -74,6 +74,7 @@ // Handles objects with the built-in `forEach`, arrays, and raw objects. // Delegates to **ECMAScript 5**'s native `forEach` if available. var each = _.each = _.forEach = function(obj, iterator, context) { + if (obj == null) return; if (nativeForEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context); } else if (obj.length === +obj.length) { @@ -93,6 +94,7 @@ // Delegates to **ECMAScript 5**'s native `map` if available. _.map = _.collect = function(obj, iterator, context) { var results = []; + if (obj == null) return results; if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); each(obj, function(value, index, list) { results[results.length] = iterator.call(context, value, index, list); @@ -104,6 +106,7 @@ // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { var initial = arguments.length > 2; + if (obj == null) obj = []; if (nativeReduce && obj.reduce === nativeReduce) { if (context) iterator = _.bind(iterator, context); return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); @@ -124,6 +127,7 @@ // Delegates to **ECMAScript 5**'s native `reduceRight` if available. _.reduceRight = _.foldr = function(obj, iterator, memo, context) { var initial = arguments.length > 2; + if (obj == null) obj = []; if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { if (context) iterator = _.bind(iterator, context); return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); @@ -163,6 +167,7 @@ // Aliased as `select`. _.filter = _.select = function(obj, iterator, context) { var results = []; + if (obj == null) return results; if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); each(obj, function(value, index, list) { if (iterator.call(context, value, index, list)) results[results.length] = value; @@ -173,6 +178,7 @@ // Return all the elements for which a truth test fails. _.reject = function(obj, iterator, context) { var results = []; + if (obj == null) return results; each(obj, function(value, index, list) { if (!iterator.call(context, value, index, list)) results[results.length] = value; }); @@ -185,6 +191,7 @@ _.every = _.all = function(obj, iterator, context) { iterator || (iterator = _.identity); var result = true; + if (obj == null) return result; if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); each(obj, function(value, index, list) { if (!(result = result && iterator.call(context, value, index, list))) return breaker; @@ -198,6 +205,7 @@ var any = _.some = _.any = function(obj, iterator, context) { iterator || (iterator = _.identity); var result = false; + if (obj == null) return result; if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); each(obj, function(value, index, list) { if (result || (result = iterator.call(context, value, index, list))) return breaker; @@ -209,6 +217,7 @@ // Aliased as `include`. _.contains = _.include = function(obj, target) { var found = false; + if (obj == null) return found; if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; found = any(obj, function(value) { return value === target; @@ -500,6 +509,7 @@ // If the array is large and already in sort order, pass `true` // for **isSorted** to use binary search. _.indexOf = function(array, item, isSorted) { + if (array == null) return -1; var i = 0, l = array.length; if (isSorted) { if (typeof isSorted == 'number') { @@ -516,6 +526,7 @@ // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. _.lastIndexOf = function(array, item, from) { + if (array == null) return -1; var hasIndex = from != null; if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); From 87cac5bd057ceafd6f779b1df33de61ca21b5e1d Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Sat, 6 Oct 2012 23:04:37 -0400 Subject: [PATCH 3/3] Underscore.js 1.4.2 --- docs/underscore.html | 15 +++++++++++++-- index.html | 21 ++++++++++++++++----- package.json | 2 +- underscore-min.js | 4 ++-- underscore.js | 4 ++-- 5 files changed, 34 insertions(+), 12 deletions(-) diff --git a/docs/underscore.html b/docs/underscore.html index 976d41eba..1f4b86a94 100644 --- a/docs/underscore.html +++ b/docs/underscore.html @@ -1,4 +1,4 @@ - underscore.js

    underscore.js

    Underscore.js 1.4.1
    +      underscore.js           

    underscore.js

    Underscore.js 1.4.2
     http://underscorejs.org
     (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
     Underscore may be freely distributed under the MIT license.
    @@ -34,9 +34,10 @@
         exports._ = _;
       } else {
         root['_'] = _;
    -  }

    Current version.

      _.VERSION = '1.4.1';

    Collection Functions

    The cornerstone, an each implementation, aka forEach. + }

    Current version.

      _.VERSION = '1.4.2';

    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.

      var each = _.each = _.forEach = function(obj, iterator, context) {
    +    if (obj == null) return;
         if (nativeForEach && obj.forEach === nativeForEach) {
           obj.forEach(iterator, context);
         } else if (obj.length === +obj.length) {
    @@ -53,6 +54,7 @@
       };

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

      _.map = _.collect = function(obj, iterator, context) {
         var results = [];
    +    if (obj == null) return results;
         if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
         each(obj, function(value, index, list) {
           results[results.length] = iterator.call(context, value, index, list);
    @@ -61,6 +63,7 @@
       };

    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 = arguments.length > 2;
    +    if (obj == null) obj = [];
         if (nativeReduce && obj.reduce === nativeReduce) {
           if (context) iterator = _.bind(iterator, context);
           return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
    @@ -78,6 +81,7 @@
       };

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

      _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
         var initial = arguments.length > 2;
    +    if (obj == null) obj = [];
         if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
           if (context) iterator = _.bind(iterator, context);
           return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
    @@ -111,6 +115,7 @@
     Delegates to ECMAScript 5's native filter if available.
     Aliased as select.

      _.filter = _.select = function(obj, iterator, context) {
         var results = [];
    +    if (obj == null) return results;
         if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
         each(obj, function(value, index, list) {
           if (iterator.call(context, value, index, list)) results[results.length] = value;
    @@ -118,6 +123,7 @@
         return results;
       };

    Return all the elements for which a truth test fails.

      _.reject = function(obj, iterator, context) {
         var results = [];
    +    if (obj == null) return results;
         each(obj, function(value, index, list) {
           if (!iterator.call(context, value, index, list)) results[results.length] = value;
         });
    @@ -127,6 +133,7 @@
     Aliased as all.

      _.every = _.all = function(obj, iterator, context) {
         iterator || (iterator = _.identity);
         var result = true;
    +    if (obj == null) return result;
         if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
         each(obj, function(value, index, list) {
           if (!(result = result && iterator.call(context, value, index, list))) return breaker;
    @@ -137,6 +144,7 @@
     Aliased as any.

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

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

      _.contains = _.include = function(obj, target) {
         var found = false;
    +    if (obj == null) return found;
         if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
         found = any(obj, function(value) {
           return value === target;
    @@ -346,6 +355,7 @@
     Delegates to ECMAScript 5's native indexOf if available.
     If the array is large and already in sort order, pass true
     for isSorted to use binary search.

      _.indexOf = function(array, item, isSorted) {
    +    if (array == null) return -1;
         var i = 0, l = array.length;
         if (isSorted) {
           if (typeof isSorted == 'number') {
    @@ -359,6 +369,7 @@
         for (; i < l; i++) if (array[i] === item) return i;
         return -1;
       };

    Delegates to ECMAScript 5's native lastIndexOf if available.

      _.lastIndexOf = function(array, item, from) {
    +    if (array == null) return -1;
         var hasIndex = from != null;
         if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
           return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
    diff --git a/index.html b/index.html
    index bbf3e07e3..71b1f5a36 100644
    --- a/index.html
    +++ b/index.html
    @@ -179,7 +179,7 @@