関数呼び出し
関数はオブジェクトの一種です。
すべての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は、呼び出されたときに何らかの方法でその情報を提供する必要があります。これは、callor 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); }};