関数呼び出し
関数はオブジェクトの一種です。
すべてのFunctionオブジェクトには、呼び出されたFunctionオブジェクトを実行するcallメソッドとapplyメソッドがあります。
呼び出されると、これらのメソッドの最初の引数this
は、関数の実行中にキーワードによって参照されるオブジェクトを指定します。null
またはundefined
、またはの場合、グローバルオブジェクトwindow
はに使用されthis
ます。
したがって、関数を呼び出す...
whereAmI = "window";
function foo()
{
return "this is " + this.whereAmI + " with " + arguments.length + " + arguments";
}
...括弧付き- foo()
-と同等であるfoo.call(undefined)
か、foo.apply(undefined)
である、効果的に同じfoo.call(window)
又はfoo.apply(window)
。
>>> foo()
"this is window with 0 arguments"
>>> foo.call()
"this is window with 0 arguments"
への追加の引数call
は、関数呼び出しへの引数として渡されますが、への単一の追加apply
の引数は、関数呼び出しの引数を配列のようなオブジェクトとして指定できます。
したがって、またはfoo(1, 2, 3)
と同等です。foo.call(null, 1, 2, 3)
foo.apply(null, [1, 2, 3])
>>> foo(1, 2, 3)
"this is window with 3 arguments"
>>> foo.apply(null, [1, 2, 3])
"this is window with 3 arguments"
関数がオブジェクトのプロパティである場合...
var obj =
{
whereAmI: "obj",
foo: foo
};
...オブジェクトを介して関数への参照にアクセスし、括弧でそれを呼び出す- obj.foo()
-と同等ですfoo.call(obj)
かfoo.apply(obj)
。
ただし、オブジェクトのプロパティとして保持されている関数は、それらのオブジェクトに「バインド」されていません。obj
上記の定義からわかるように、関数は単なるオブジェクトのタイプなので、参照することができます(したがって、関数呼び出しへの参照によって渡すことも、関数呼び出しからの参照によって返すこともできます)。関数への参照が渡されると、それがどこから渡されたのかについての追加情報は伝達されません。そのため、次のことが起こります。
>>> baz = obj.foo;
>>> baz();
"this is window with 0 arguments"
関数リファレンスbaz
への呼び出しは、呼び出しのコンテキストを提供しないため、と実質的に同じなbaz.call(undefined)
ので、this
最終的にを参照しますwindow
。baz
それがに属していることを知りたいobj
場合baz
は、呼び出されたときに何らかの方法でその情報を提供する必要があります。これは、call
or apply
とクロージャの最初の引数が機能する場所です。
スコープチェーン
function bind(func, context)
{
return function()
{
func.apply(context, arguments);
};
}
関数が実行されると、新しいスコープが作成され、それを囲むスコープへの参照が含まれます。匿名の関数が上記の例で作成されたとき、それはそれが作成されたスコープへの参照を持っています、それはbind
のスコープです。これは「クロージャー」として知られています。
[global scope (window)] - whereAmI, foo, obj, baz
|
[bind scope] - func, context
|
[anonymous scope]
変数にアクセスしようとすると、この「スコープチェーン」をたどって、指定された名前の変数が見つかります。現在のスコープに変数が含まれていない場合は、チェーン内の次のスコープを調べます。グローバルスコープ。無名関数が返されてbind
実行が終了しても、無名関数はまだbind
のスコープへの参照を持っているため、bind
のスコープは「消えません」。
上記のすべてを考慮すると、次の例でスコープがどのように機能するか、および特定の値で「事前結合」の周りに関数を渡す手法this
が呼び出されたときに機能する理由を理解できるはずです。
>>> baz = bind(obj.foo, obj);
>>> baz(1, 2);
"this is obj with 2 arguments"
var signup = { onLoadHandler:function(){ console.log(this); return Type.createDelegate(this,this._onLoad); }, _onLoad: function (s, a) { console.log("this",this); }};