From 240bc40b39ceb29b8eca71f64f2aedd7e918db77 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 4 Jun 2012 15:21:49 -0400 Subject: [PATCH] Ensure collection methods treat array-like objects with invalid `length` properties as regular objects. Former-commit-id: dd8b382635bc30dc6e417cd9b47c36abfdf5ddcb --- lodash.js | 8 ++++---- test/test.js | 26 +++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/lodash.js b/lodash.js index 58b37c470..e86014e81 100644 --- a/lodash.js +++ b/lodash.js @@ -215,7 +215,7 @@ // the following branch is for iterating arrays and array-like objects '<% if (arrayBranch) { %>' + 'var length = <%= firstArg %>.length; index = -1;' + - ' <% if (objectBranch) { %>\nif (typeof length == \'number\') {<% } %>\n' + + ' <% if (objectBranch) { %>\nif (typeof length === length >>> 0) {<% } %>\n' + ' <%= arrayBranch.beforeLoop %>;\n' + ' while (<%= arrayBranch.loopExp %>) {\n' + ' <%= arrayBranch.inLoop %>;\n' + @@ -804,7 +804,7 @@ if(thisArg) { callback = iteratorBind(callback, thisArg); } - if (typeof length == 'number') { + if (length === length >>> 0) { if (length && noaccum) { accumulator = collection[--length]; } @@ -895,7 +895,7 @@ return collection.toArray(); } var length = collection.length; - if (typeof length == 'number') { + if (length === length >>> 0) { return slice.call(collection); } return values(collection); @@ -3391,7 +3391,7 @@ } // IE compatibility mode and IE < 9 have buggy Array `shift()` and `splice()` // functions that fail to remove the last element, `value[0]`, of - // array-like-objects even though the `length` property is set to `0`. + // array-like objects even though the `length` property is set to `0`. // The `shift()` method is buggy in IE 8 compatibility mode, while `splice()` // is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9. if (value.length === 0) { diff --git a/test/test.js b/test/test.js index 23b000e18..8962a574c 100644 --- a/test/test.js +++ b/test/test.js @@ -233,6 +233,14 @@ var collection = [1, 2, 3]; equal(_.forEach(collection, Boolean), collection); }); + + test('should treat array-like object with invalid `length` as a regular object', function() { + var keys = [], + object = { 'length': -1 }; + + _.forEach(object, function(value, key) { keys.push(key); }); + deepEqual(keys, ['length']); + }); }()); /*--------------------------------------------------------------------------*/ @@ -521,6 +529,17 @@ deepEqual(args, ['C', 'B', 'b', object]); }); + + test('should treat array-like object with invalid `length` as a regular object', function() { + var args, + object = { 'a': 'A', 'length': -1 }; + + _.reduceRight(object, function() { + args || (args = slice.call(arguments)); + }); + + deepEqual(args, [-1, 'A', 'a', object]); + }); }()); /*--------------------------------------------------------------------------*/ @@ -622,11 +641,16 @@ deepEqual(_.toArray(array), [3, 2, 1]); }); - test('should treat array-like-objects like arrays', function() { + test('should treat array-like objects like arrays', function() { var object = { '0': 'a', '1': 'b', '2': 'c', 'length': 3 }; deepEqual(_.toArray(object), ['a', 'b', 'c']); deepEqual(_.toArray(args), [1, 2, 3]); }); + + test('should treat array-like object with invalid `length` as a regular object', function() { + var object = { 'length': -1 }; + deepEqual(_.toArray(object), [-1]); + }); }(1, 2, 3)); /*--------------------------------------------------------------------------*/