From 2d886a4bcea93761b8c1d83a8523a07ea5574f4e Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 8 Jul 2014 15:09:26 -0400 Subject: [PATCH] forEach passes object being iterated over as 3rd arg to callbacks This is for consistency with native Array.prototype.forEach() API, and it is also sometimes useful! --- src/Angular.js | 17 ++++++++++------- test/AngularSpec.js | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/Angular.js b/src/Angular.js index eaaf2f37bc75..b638ee55de57 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -210,9 +210,10 @@ function isArrayLike(obj) { * * @description * Invokes the `iterator` function once for each item in `obj` collection, which can be either an - * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value` - * is the value of an object property or an array element and `key` is the object property key or - * array element index. Specifying a `context` for the function is optional. + * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where + * `value` is the value of an object property or an array element, `key` is the object property + * key or array element index, and `obj` is a reference to the collection being iterated over. + * Specifying a `context` for the function is optional. * * It is worth noting that `.forEach` does not iterate over inherited properties because it filters * using the `hasOwnProperty` method. @@ -239,20 +240,22 @@ function forEach(obj, iterator, context) { for (key in obj) { // Need to check if hasOwnProperty exists, // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function - if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) { - iterator.call(context, obj[key], key); + if (key !== 'prototype' && key !== 'length' && key !== 'name' && + (!obj.hasOwnProperty || obj.hasOwnProperty(key))) { + iterator.call(context, obj[key], key, obj); } } } else if (isArray(obj) || isArrayLike(obj)) { + // for loop is actually faster than native Array.prototype.forEach() for (key = 0, length = obj.length; key < length; key++) { - iterator.call(context, obj[key], key); + iterator.call(context, obj[key], key, obj); } } else if (obj.forEach && obj.forEach !== forEach) { obj.forEach(iterator, context); } else { for (key in obj) { if (obj.hasOwnProperty(key)) { - iterator.call(context, obj[key], key); + iterator.call(context, obj[key], key, obj); } } } diff --git a/test/AngularSpec.js b/test/AngularSpec.js index 6a74c6c615b9..b7c815337034 100644 --- a/test/AngularSpec.js +++ b/test/AngularSpec.js @@ -634,6 +634,26 @@ describe('angular', function() { forEach(obj, function(value, key) { log.push(key + ':' + value); }); expect(log).toEqual(['length:2', 'foo:bar']); }); + + + it('should pass object being iterated over as 3rd arg to callbacks', function() { + var obj = {foo: 'bar'}, + arr = [1], + func = function () {}; + + forEach(obj, function (value, key, collection) { + expect(obj).toBe(collection); + }); + + forEach(arr, function (value, index, collection) { + expect(arr).toBe(collection); + }); + + func.foo = 'bar'; + forEach(func, function (value, key, collection) { + expect(func).toBe(collection); + }); + }); });