Closure:Michael BolinによるThe Definitive Guideの抜粋に従います。少し長く見えるかもしれませんが、多くの洞察で飽和しています。「付録B.よく誤解されているJavaScriptの概念」から:
this
関数が呼び出されたときの意味
フォームの関数を呼び出すときfoo.bar.baz()
、オブジェクトfoo.bar
はレシーバーと呼ばれます。関数が呼び出されると、次の値として使用されるのはレシーバですthis
。
var obj = {};
obj.value = 10;
/** @param {...number} additionalValues */
obj.addValues = function(additionalValues) {
for (var i = 0; i < arguments.length; i++) {
this.value += arguments[i];
}
return this.value;
};
// Evaluates to 30 because obj is used as the value for 'this' when
// obj.addValues() is called, so obj.value becomes 10 + 20.
obj.addValues(20);
関数が呼び出されたときに明示的なレシーバーがない場合、グローバルオブジェクトがレシーバーになります。47ページの「goog.global」で説明されているように、JavaScriptがWebブラウザーで実行されるときのwindowはグローバルオブジェクトです。これはいくつかの驚くべき動作につながります:
var f = obj.addValues;
// Evaluates to NaN because window is used as the value for 'this' when
// f() is called. Because and window.value is undefined, adding a number to
// it results in NaN.
f(20);
// This also has the unintentional side effect of adding a value to window:
alert(window.value); // Alerts NaN
同じ関数obj.addValues
をf
参照していても、レシーバーの値は呼び出しごとに異なるため、呼び出されたときの動作は異なります。このため、を参照する関数を呼び出すときは、が呼び出されたときにが正しい値になるthis
ようにすることが重要this
です。明確にするためthis
に、関数本体で参照されていない場合、f(20)
およびの動作はobj.addValues(20)
同じになります。
関数はJavaScriptのファーストクラスオブジェクトであるため、独自のメソッドを持つことができます。すべての関数にはメソッドがcall()
あり、関数を呼び出すときにapply()
レシーバー(つまり、参照するオブジェクトthis
)を再定義することができます。メソッドのシグネチャは次のとおりです。
/**
* @param {*=} receiver to substitute for 'this'
* @param {...} parameters to use as arguments to the function
*/
Function.prototype.call;
/**
* @param {*=} receiver to substitute for 'this'
* @param {Array} parameters to use as arguments to the function
*/
Function.prototype.apply;
なお、唯一の違いcall()
とapply()
つまりcall()
、一方、個々の引数として関数パラメータを受信するapply()
単一のアレイとしてそれらを受信します。
// When f is called with obj as its receiver, it behaves the same as calling
// obj.addValues(). Both of the following increase obj.value by 60:
f.call(obj, 10, 20, 30);
f.apply(obj, [10, 20, 30]);
次の呼び出しは同等でf
ありobj.addValues
、同じ関数を参照しています。
obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);
しかしながら、どちらcall()
もapply()
それが指定されていない受信機の引数の代わりに独自の受信機の値を使用して、次の意志ではない作品。
// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);
値はthis
缶がなることはありませんnull
か、undefined
関数が呼び出されたとき。場合null
又はundefined
受信機として供給されるcall()
、またはapply()
、グローバルオブジェクトではなく、受信機のための値として使用されます。したがって、前のコードにはvalue
、グローバルオブジェクトに名前が付けられたプロパティを追加するのと同じ望ましくない副作用があります。
関数は、それが割り当てられている変数を認識していないものと考えると役に立ちます。これは、関数の定義時ではなく、関数が呼び出されたときに、この値がバインドされるという考えを強化するのに役立ちます。
抽出の終わり。
a
argsの配列の適用と、argsのc
列の呼び出しについて考えます。