diff --git a/test/collections.js b/test/collections.js index 1726629eb..857ae3731 100644 --- a/test/collections.js +++ b/test/collections.js @@ -1,4 +1,4 @@ -$(document).ready(function() { +$(document).ready(function($, undefined) { module("Collections"); @@ -8,7 +8,7 @@ $(document).ready(function() { }); var answers = []; - _.each([1, 2, 3], function(num){ answers.push(num * this.multiplier);}, {multiplier : 5}); + _.each([1, 2, 3], function(num){ answers.push(num * this.multiplier); }, {multiplier : 5}); equals(answers.join(', '), '5, 10, 15', 'context object property accessed'); answers = []; @@ -75,15 +75,14 @@ $(document).ready(function() { 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'); + equals(_.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'); - // Sparse arrays: - var sparseArray = []; - sparseArray[100] = 10; - sparseArray[200] = 20; - - equals(_.reduce(sparseArray, function(a, b){ return a + b }), 30, 'initially-sparse arrays with no memo'); + var sparseArray = []; + sparseArray[0] = 20; + sparseArray[2] = -5; + equals(_.reduce(sparseArray, function(a, b){ return a - b }), 25, 'initially-sparse arrays with no memo'); }); test('collections: reduceRight', function() { @@ -103,8 +102,14 @@ $(document).ready(function() { ifnull = ex; } ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly'); - ok(_.reduceRight(null, function(){}, 138) === 138, 'handles a null (with initial value) properly'); + equals(_.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'); + + var sparseArray = []; + sparseArray[0] = 20; + sparseArray[2] = -5; + equals(_.reduceRight(sparseArray, function(a, b){ return a - b }), -25, 'initially-sparse arrays with no memo'); }); test('collections: detect', function() { diff --git a/test/objects.js b/test/objects.js index 6d432033a..fbcc02a39 100644 --- a/test/objects.js +++ b/test/objects.js @@ -1,18 +1,17 @@ -$(document).ready(function() { +$(document).ready(function($, undefined) { module("Objects"); test("objects: keys", function() { - var exception = /object/; equals(_.keys({one : 1, two : 2}).join(', '), 'one, two', 'can extract the keys from an object'); // the test above is not safe because it relies on for-in enumeration order var a = []; a[1] = 0; equals(_.keys(a).join(', '), '1', 'is not fooled by sparse arrays; see issue #95'); - raises(function() { _.keys(null); }, exception, 'throws an error for `null` values'); - raises(function() { _.keys(void 0); }, exception, 'throws an error for `undefined` values'); - raises(function() { _.keys(1); }, exception, 'throws an error for number primitives'); - raises(function() { _.keys('a'); }, exception, 'throws an error for string primitives'); - raises(function() { _.keys(true); }, exception, 'throws an error for boolean primitives'); + raises(function() { _.keys(null); }, TypeError, 'throws an error for `null` values'); + raises(function() { _.keys(void 0); }, TypeError, 'throws an error for `undefined` values'); + raises(function() { _.keys(1); }, TypeError, 'throws an error for number primitives'); + raises(function() { _.keys('a'); }, TypeError, 'throws an error for string primitives'); + raises(function() { _.keys(true); }, TypeError, 'throws an error for boolean primitives'); }); test("objects: values", function() { diff --git a/underscore.js b/underscore.js index e535966b3..19f374db9 100644 --- a/underscore.js +++ b/underscore.js @@ -167,7 +167,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 = memo !== void 0; + var initial = arguments.length > 2; if (obj == null) obj = []; if (nativeReduce && obj.reduce === nativeReduce) { if (context) iterator = _.bind(iterator, context); @@ -181,20 +181,22 @@ memo = iterator.call(context, memo, value, index, list); } }); - if (!initial) throw new TypeError("Reduce of empty array with no initial value"); + if (!initial) throw new TypeError('Reduce of empty array with no initial value'); return memo; }; // 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 memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); + return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); } - var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse(); - return _.reduce(reversed, iterator, memo, context); + var reversed = _.toArray(obj).reverse(); + if (context && !initial) iterator = _.bind(iterator, context); + return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator); }; // Return the first value which passes a truth test. Aliased as `detect`.