Array#forEachの話

引数があった場合はそのオブジェクトにしたいってことはわかったのだがなぜ引数無しで動作するのかがわからない。

気になったので調べてみた。おそらくこんな感じではないでしょうか。

Array.prototype.forEach = function(fun /*, thisp*/)
{
  var len = this.length;
  if (typeof fun != "function")
    throw new TypeError();
  var thisp = arguments[1];
  for (var i = 0; i < len; i++)
  {
    if (i in this)
      fun.call(thisp, this[i], i, this);
  }
};

function printElt(element, index, array) {
    alert(this); // [object Window]
}
[2, 5, 9].forEach(printElt);

まず、Array#forEach の引数が一つしかないので arguments[1] は undefined となります。すると以下の部分、

fun.call(thisp, this[i], i, this);

Function#call の第一引数に undefined が指定された事になります。Function#call は、自分自身を第一引数で指定したオブジェクトのメソッドとして実行するというものですが、第一引数に null や undefined が指定された場合、グローバルオブジェクトのコンテキストで実行されます。

Function オブジェクト F の Call プロパティが呼出されるとき、次のステップが取られる:

  1. F の FormalParameterList を用いる、新しい実行コンテキストを設置し、引数リストとセクション 10.2.3 で述べる this 値を渡す。

セクション 10.2.3 で述べる this 値とは…

this 値は呼出側が提供する。呼出側が提供する this 値がオブジェクトでない場合(null である場合を含む)、 this 値はグローバルオブジェクトとする。

よって

function printElt(element, index, array) {
    alert(this); // [object Window]
}
[2, 5, 9].forEach(printElt);

thisはグローバルオブジェクト、すなわちWindowになります。たぶん…