Explanation
It's already in the documentation (emphasis mine):
15.4.4.18 Array.prototype.forEach ( callbackfn [ , thisArg ] )
callbackfn should be a function that accepts three arguments.
forEach calls callbackfn once for each element present in the
array, in ascending order. callbackfn is called only for elements of
the array which actually exist; it is not called for missing elements
of the array.
If a thisArg parameter is provided, it will be used as the this
value for each invocation of callbackfn. If it is not provided,
undefined is used instead.
thisArg is only used in the invocation of callbackfn. It's not, however, used to provide the this value for forEach, where this needs to be an array like structure (that means it has a length property). If you use Array.prototype.forEach(..., someObject), the this value in forEach's context will be undefined.
Simplified forEach version (which shows the problem immediately)
function forEach( callback , thisArg ){
// The algorithm parses the length as UInt32, see step 3.
// >>> not only acts as bit shift, but also forces the
// value into an unsigned number.
var len = this.length >>> 0, // using "this", not "thisArg"!
i;
for(i = 0; i < len; ++i){
callback.call(thisArg, this[i]);
// thisArg ^^^^^^^^^ is used here, not up at length
}
}
// example calls:
var logArguments = function(args){
console.log(args, this);
}
forEach(logArguments, [1,2,3]); // logs nothing
forEach.call([1,2,3], logArguments); // logs 1, 2, 3
forEach.call([1,2,3], logArguments, [2,3,4]); // logs "1 Array [2,3,4]"
// "2 Array [2,3,4]"
// "3 Array [2,3,4]"