Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit df9e60c

Browse files
jbedardIgorMinar
authored andcommitted
feat(angular.forEach): add the array/object as the 3rd param like the native array forEach
Closes #7902
1 parent 41cec4d commit df9e60c

File tree

2 files changed

+77
-8
lines changed

2 files changed

+77
-8
lines changed

src/Angular.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,9 @@ function isArrayLike(obj) {
210210
*
211211
* @description
212212
* Invokes the `iterator` function once for each item in `obj` collection, which can be either an
213-
* object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
214-
* is the value of an object property or an array element and `key` is the object property key or
215-
* array element index. Specifying a `context` for the function is optional.
213+
* object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
214+
* is the value of an object property or an array element, `key` is the object property key or
215+
* array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
216216
*
217217
* It is worth noting that `.forEach` does not iterate over inherited properties because it filters
218218
* using the `hasOwnProperty` method.
@@ -240,22 +240,22 @@ function forEach(obj, iterator, context) {
240240
// Need to check if hasOwnProperty exists,
241241
// as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
242242
if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
243-
iterator.call(context, obj[key], key);
243+
iterator.call(context, obj[key], key, obj);
244244
}
245245
}
246246
} else if (isArray(obj) || isArrayLike(obj)) {
247247
var isPrimitive = typeof obj !== 'object';
248248
for (key = 0, length = obj.length; key < length; key++) {
249249
if (isPrimitive || key in obj) {
250-
iterator.call(context, obj[key], key);
250+
iterator.call(context, obj[key], key, obj);
251251
}
252252
}
253253
} else if (obj.forEach && obj.forEach !== forEach) {
254-
obj.forEach(iterator, context);
254+
obj.forEach(iterator, context, obj);
255255
} else {
256256
for (key in obj) {
257257
if (obj.hasOwnProperty(key)) {
258-
iterator.call(context, obj[key], key);
258+
iterator.call(context, obj[key], key, obj);
259259
}
260260
}
261261
}

test/AngularSpec.js

+70-1
Original file line numberDiff line numberDiff line change
@@ -654,10 +654,79 @@ describe('angular', function() {
654654
var log = [];
655655
var collection = [];
656656
collection[5] = 'SPARSE';
657-
forEach(collection, function (item, index) { log.push(item + index); });
657+
forEach(collection, function (item, index) {
658+
log.push(item + index);
659+
});
658660
expect(log.length).toBe(1);
659661
expect(log[0]).toBe('SPARSE5');
660662
});
663+
664+
665+
describe('ES spec api compliance', function() {
666+
667+
function testForEachSpec(expectedSize, collection) {
668+
var that = {};
669+
670+
forEach(collection, function(value, key, collectionArg) {
671+
expect(collectionArg).toBe(collection);
672+
expect(collectionArg[key]).toBe(value);
673+
674+
expect(this).toBe(that);
675+
676+
expectedSize--;
677+
}, that);
678+
679+
expect(expectedSize).toBe(0);
680+
}
681+
682+
683+
it('should follow the ES spec when called with array', function() {
684+
testForEachSpec(2, [1,2]);
685+
});
686+
687+
688+
it('should follow the ES spec when called with arguments', function() {
689+
testForEachSpec(2, (function(){ return arguments; }(1,2)));
690+
});
691+
692+
693+
it('should follow the ES spec when called with string', function() {
694+
testForEachSpec(2, '12');
695+
});
696+
697+
698+
it('should follow the ES spec when called with jQuery/jqLite', function() {
699+
testForEachSpec(2, jqLite("<span>a</span><span>b</span>"));
700+
});
701+
702+
703+
it('should follow the ES spec when called with childNodes NodeList', function() {
704+
testForEachSpec(2, jqLite("<p><span>a</span><span>b</span></p>")[0].childNodes);
705+
});
706+
707+
708+
it('should follow the ES spec when called with getElementsByTagName HTMLCollection', function() {
709+
testForEachSpec(2, jqLite("<p><span>a</span><span>b</span></p>")[0].getElementsByTagName("*"));
710+
});
711+
712+
713+
it('should follow the ES spec when called with querySelectorAll HTMLCollection', function() {
714+
testForEachSpec(2, jqLite("<p><span>a</span><span>b</span></p>")[0].querySelectorAll("*"));
715+
});
716+
717+
718+
it('should follow the ES spec when called with JSON', function() {
719+
testForEachSpec(2, {a: 1, b: 2});
720+
});
721+
722+
723+
it('should follow the ES spec when called with function', function() {
724+
function f(){}
725+
f.a = 1;
726+
f.b = 2;
727+
testForEachSpec(2, f);
728+
});
729+
});
661730
});
662731

663732

0 commit comments

Comments
 (0)