mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-07 18:07:49 +00:00
Improve compliance with Array methods in ES5 when passed a null value. (ES5 Array methods treat null like [])
This commit is contained in:
@@ -83,6 +83,7 @@ $(document).ready(function() {
|
|||||||
equals(_.indexOf(numbers, 2), 1, 'can compute indexOf, even without the native function');
|
equals(_.indexOf(numbers, 2), 1, 'can compute indexOf, even without the native function');
|
||||||
var result = (function(){ return _.indexOf(arguments, 2); })(1, 2, 3);
|
var result = (function(){ return _.indexOf(arguments, 2); })(1, 2, 3);
|
||||||
equals(result, 1, 'works on an arguments object');
|
equals(result, 1, 'works on an arguments object');
|
||||||
|
equals(_.indexOf(null, 2), -1, 'handles nulls properly');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("arrays: lastIndexOf", function() {
|
test("arrays: lastIndexOf", function() {
|
||||||
@@ -92,6 +93,7 @@ $(document).ready(function() {
|
|||||||
equals(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element');
|
equals(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element');
|
||||||
var result = (function(){ return _.lastIndexOf(arguments, 1); })(1, 0, 1, 0, 0, 1, 0, 0, 0);
|
var result = (function(){ return _.lastIndexOf(arguments, 1); })(1, 0, 1, 0, 0, 1, 0, 0, 0);
|
||||||
equals(result, 5, 'works on an arguments object');
|
equals(result, 5, 'works on an arguments object');
|
||||||
|
equals(_.indexOf(null, 2), -1, 'handles nulls properly');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("arrays: range", function() {
|
test("arrays: range", function() {
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ $(document).ready(function() {
|
|||||||
answers = [];
|
answers = [];
|
||||||
_.each({range : 1, speed : 2, length : 3}, function(v){ answers.push(v); });
|
_.each({range : 1, speed : 2, length : 3}, function(v){ answers.push(v); });
|
||||||
ok(answers.join(', '), '1, 2, 3', 'can iterate over objects with numeric length properties');
|
ok(answers.join(', '), '1, 2, 3', 'can iterate over objects with numeric length properties');
|
||||||
|
|
||||||
|
answers = 0;
|
||||||
|
_.each(null, function(){ ++answers; });
|
||||||
|
equals(answers, 0, 'handles a null properly');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('collections: map', function() {
|
test('collections: map', function() {
|
||||||
@@ -46,6 +50,9 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
var ids = _.map(document.images, function(n){ return n.id; });
|
var ids = _.map(document.images, function(n){ return n.id; });
|
||||||
ok(ids[0] == 'chart_image', 'can use collection methods on HTMLCollections');
|
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('collections: reduce', function() {
|
test('collections: reduce', function() {
|
||||||
@@ -64,6 +71,16 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; });
|
var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; });
|
||||||
equals(sum, 6, 'default initial value');
|
equals(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');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('collections: reduceRight', function() {
|
test('collections: reduceRight', function() {
|
||||||
@@ -75,6 +92,16 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; });
|
var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; });
|
||||||
equals(list, 'bazbarfoo', 'default initial value');
|
equals(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');
|
||||||
|
|
||||||
|
ok(_.reduceRight(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('collections: detect', function() {
|
test('collections: detect', function() {
|
||||||
|
|||||||
@@ -68,6 +68,7 @@
|
|||||||
// Delegates to **ECMAScript 5**'s native `forEach` if available.
|
// Delegates to **ECMAScript 5**'s native `forEach` if available.
|
||||||
var each = _.each = _.forEach = function(obj, iterator, context) {
|
var each = _.each = _.forEach = function(obj, iterator, context) {
|
||||||
var value;
|
var value;
|
||||||
|
if (obj == null) return;
|
||||||
if (nativeForEach && obj.forEach === nativeForEach) {
|
if (nativeForEach && obj.forEach === nativeForEach) {
|
||||||
obj.forEach(iterator, context);
|
obj.forEach(iterator, context);
|
||||||
} else if (_.isNumber(obj.length)) {
|
} else if (_.isNumber(obj.length)) {
|
||||||
@@ -86,8 +87,9 @@
|
|||||||
// Return the results of applying the iterator to each element.
|
// Return the results of applying the iterator to each element.
|
||||||
// Delegates to **ECMAScript 5**'s native `map` if available.
|
// Delegates to **ECMAScript 5**'s native `map` if available.
|
||||||
_.map = function(obj, iterator, context) {
|
_.map = function(obj, iterator, context) {
|
||||||
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
|
|
||||||
var results = [];
|
var results = [];
|
||||||
|
if (obj == null) return results;
|
||||||
|
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
|
||||||
each(obj, function(value, index, list) {
|
each(obj, function(value, index, list) {
|
||||||
results[results.length] = iterator.call(context, value, index, list);
|
results[results.length] = iterator.call(context, value, index, list);
|
||||||
});
|
});
|
||||||
@@ -98,6 +100,7 @@
|
|||||||
// or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
|
// or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
|
||||||
_.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
|
_.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
|
||||||
var initial = memo !== void 0;
|
var initial = memo !== void 0;
|
||||||
|
if (obj == null) obj = [];
|
||||||
if (nativeReduce && obj.reduce === nativeReduce) {
|
if (nativeReduce && obj.reduce === nativeReduce) {
|
||||||
if (context) iterator = _.bind(iterator, context);
|
if (context) iterator = _.bind(iterator, context);
|
||||||
return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
|
return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
|
||||||
@@ -105,16 +108,19 @@
|
|||||||
each(obj, function(value, index, list) {
|
each(obj, function(value, index, list) {
|
||||||
if (!initial && index === 0) {
|
if (!initial && index === 0) {
|
||||||
memo = value;
|
memo = value;
|
||||||
|
initial = true;
|
||||||
} else {
|
} else {
|
||||||
memo = iterator.call(context, memo, value, index, list);
|
memo = iterator.call(context, memo, value, index, list);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (!initial) throw new TypeError("Reduce of empty array with no initial value");
|
||||||
return memo;
|
return memo;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The right-associative version of reduce, also known as `foldr`.
|
// The right-associative version of reduce, also known as `foldr`.
|
||||||
// Delegates to **ECMAScript 5**'s native `reduceRight` if available.
|
// Delegates to **ECMAScript 5**'s native `reduceRight` if available.
|
||||||
_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
|
_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
|
||||||
|
if (obj == null) obj = [];
|
||||||
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
|
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
|
||||||
if (context) iterator = _.bind(iterator, context);
|
if (context) iterator = _.bind(iterator, context);
|
||||||
return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
|
return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
|
||||||
@@ -139,8 +145,9 @@
|
|||||||
// Delegates to **ECMAScript 5**'s native `filter` if available.
|
// Delegates to **ECMAScript 5**'s native `filter` if available.
|
||||||
// Aliased as `select`.
|
// Aliased as `select`.
|
||||||
_.filter = _.select = function(obj, iterator, context) {
|
_.filter = _.select = function(obj, iterator, context) {
|
||||||
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
|
|
||||||
var results = [];
|
var results = [];
|
||||||
|
if (obj == null) return results;
|
||||||
|
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
|
||||||
each(obj, function(value, index, list) {
|
each(obj, function(value, index, list) {
|
||||||
if (iterator.call(context, value, index, list)) results[results.length] = value;
|
if (iterator.call(context, value, index, list)) results[results.length] = value;
|
||||||
});
|
});
|
||||||
@@ -150,6 +157,7 @@
|
|||||||
// Return all the elements for which a truth test fails.
|
// Return all the elements for which a truth test fails.
|
||||||
_.reject = function(obj, iterator, context) {
|
_.reject = function(obj, iterator, context) {
|
||||||
var results = [];
|
var results = [];
|
||||||
|
if (obj == null) return results;
|
||||||
each(obj, function(value, index, list) {
|
each(obj, function(value, index, list) {
|
||||||
if (!iterator.call(context, value, index, list)) results[results.length] = value;
|
if (!iterator.call(context, value, index, list)) results[results.length] = value;
|
||||||
});
|
});
|
||||||
@@ -161,8 +169,9 @@
|
|||||||
// Aliased as `all`.
|
// Aliased as `all`.
|
||||||
_.every = _.all = function(obj, iterator, context) {
|
_.every = _.all = function(obj, iterator, context) {
|
||||||
iterator = iterator || _.identity;
|
iterator = iterator || _.identity;
|
||||||
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
|
|
||||||
var result = true;
|
var result = true;
|
||||||
|
if (obj == null) return result;
|
||||||
|
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
|
||||||
each(obj, function(value, index, list) {
|
each(obj, function(value, index, list) {
|
||||||
if (!(result = result && iterator.call(context, value, index, list))) return breaker;
|
if (!(result = result && iterator.call(context, value, index, list))) return breaker;
|
||||||
});
|
});
|
||||||
@@ -174,8 +183,9 @@
|
|||||||
// Aliased as `any`.
|
// Aliased as `any`.
|
||||||
var any = _.some = _.any = function(obj, iterator, context) {
|
var any = _.some = _.any = function(obj, iterator, context) {
|
||||||
iterator = iterator || _.identity;
|
iterator = iterator || _.identity;
|
||||||
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
|
|
||||||
var result = false;
|
var result = false;
|
||||||
|
if (obj == null) return result;
|
||||||
|
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
|
||||||
each(obj, function(value, index, list) {
|
each(obj, function(value, index, list) {
|
||||||
if (result = iterator.call(context, value, index, list)) return breaker;
|
if (result = iterator.call(context, value, index, list)) return breaker;
|
||||||
});
|
});
|
||||||
@@ -185,8 +195,9 @@
|
|||||||
// Determine if a given value is included in the array or object using `===`.
|
// Determine if a given value is included in the array or object using `===`.
|
||||||
// Aliased as `contains`.
|
// Aliased as `contains`.
|
||||||
_.include = _.contains = function(obj, target) {
|
_.include = _.contains = function(obj, target) {
|
||||||
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
|
|
||||||
var found = false;
|
var found = false;
|
||||||
|
if (obj == null) return found;
|
||||||
|
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
|
||||||
any(obj, function(value) {
|
any(obj, function(value) {
|
||||||
if (found = value === target) return true;
|
if (found = value === target) return true;
|
||||||
});
|
});
|
||||||
@@ -346,6 +357,7 @@
|
|||||||
// item in an array, or -1 if the item is not included in the array.
|
// item in an array, or -1 if the item is not included in the array.
|
||||||
// Delegates to **ECMAScript 5**'s native `indexOf` if available.
|
// Delegates to **ECMAScript 5**'s native `indexOf` if available.
|
||||||
_.indexOf = function(array, item) {
|
_.indexOf = function(array, item) {
|
||||||
|
if (array == null) return -1;
|
||||||
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
|
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
|
||||||
for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
|
for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -354,6 +366,7 @@
|
|||||||
|
|
||||||
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
|
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
|
||||||
_.lastIndexOf = function(array, item) {
|
_.lastIndexOf = function(array, item) {
|
||||||
|
if (array == null) return -1;
|
||||||
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
|
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
|
||||||
var i = array.length;
|
var i = array.length;
|
||||||
while (i--) if (array[i] === item) return i;
|
while (i--) if (array[i] === item) return i;
|
||||||
|
|||||||
Reference in New Issue
Block a user