From 8801d9c2865ae74db4f4ce755764a9f46c49c9f8 Mon Sep 17 00:00:00 2001 From: Igor Minar Date: Mon, 11 Feb 2013 12:25:34 -0800 Subject: fix(angular.forEach): correctly iterate over objects with length prop Should handle JQLite, jQuery, NodeList and other objects like arrays but not other generic objects or instances of user defined types with length property. Closes #1840 --- src/Angular.js | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'src/Angular.js') diff --git a/src/Angular.js b/src/Angular.js index 2affd5ef..4685dbde 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -90,6 +90,30 @@ var /** holds major version number for IE or NaN for real browsers */ * @param {Object=} context Object to become context (`this`) for the iterator function. * @returns {Object|Array} Reference to `obj`. */ + + +/** + * @private + * @param {*} obj + * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...) + */ +function isArrayLike(obj) { + if (!obj || (typeof obj.length !== 'number')) return false; + + // We have on object which has length property. Should we treat it as array? + if (typeof obj.hasOwnProperty != 'function' && + typeof obj.constructor != 'function') { + // This is here for IE8: it is a bogus object treat it as array; + return true; + } else { + return obj instanceof JQLite || // JQLite + (jQuery && obj instanceof jQuery) || // jQuery + toString.call(obj) !== '[object Object]' || // some browser native object + typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj) + } +} + + function forEach(obj, iterator, context) { var key; if (obj) { @@ -101,7 +125,7 @@ function forEach(obj, iterator, context) { } } else if (obj.forEach && obj.forEach !== forEach) { obj.forEach(iterator, context); - } else if (isObject(obj) && isNumber(obj.length)) { + } else if (isArrayLike(obj)) { for (key = 0; key < obj.length; key++) iterator.call(context, obj[key], key); } else { -- cgit v1.2.3