このキーワードは、JavaScript の中で最も複雑なメカニズムの 1 つです。これは、すべての関数のスコープ内で自動的に定義される非常に特殊なキーワードです。しかし、経験豊富な JavaScript 開発者でも、それが正確に何を指しているのかを理解するのは困難です。 ######これは何ですか?
関数自体を指しますか?
文字通りの意味を見ると、これは関数自体を指していると思われがちですが、本当にそうでしょうか?例を見てみましょう。
function foo() { this.count = this.count ? this.count + 1 : 1; } for (let i = 0; i < 5; i++) { foo(); } console.log(foo.count); // undefined
ご覧のとおり、foo.count の出力は予想した
5 ではなく、最初に割り当てられた 0
です。言い換えれば、this は実際には関数自体を指しているわけではありません
。 スコープを指しますか?
もう 1 つのよくある誤解は、これが関数のスコープを指しているということです。
function foo() { var a = 2; bar(); } function bar() { console.log(this.a); } foo(); // undefined
このコードでは、bar は foo で実行され、
this.a の出力は unknown
です。言い換えれば、this は関数のスコープを指す
ではありません。 これじゃない、あれじゃない、これは何ですか?
これのバインディング ルール
これのバインディングには 4 つのルールがあり、以下で 1 つずつ紹介します。
1. デフォルトのバインディング
独立した関数呼び出しは、非厳密モードでは window を指し、厳密モードでは未定義を指します。 ここで述べる独立関数は、以下の 3 つの状況を除いて、一般的な関数呼び出しとして理解できます。 <pre class="brush:php;toolbar:false">// 非严格模式
var name = 'Willem';
function foo() {
console.log(this.name);
}
foo(); // Willem
// 执行时启用严格模式
(function() {
'use strict';
foo(); // Willem
bar(); // Cannot read property 'name' of undefined
})();
// 函数体使用严格模式
function bar() {
'use strict';
console.log(this.name);
}</pre>
上記のコードでは、Willem が通常の環境で出力され、それが確かにポイントされているウィンドウ オブジェクトであることを示しています。特別な注意が必要な点が 1 つあります。
2. 暗黙的なバインディング
暗黙的なバインディングとは、関数の実行時に
がオブジェクトによって所有されるか、またはオブジェクトに含まれるかを指します。言い換えると、関数が実行されているとき、それがオブジェクトの属性として実行されているかどうかはあまり明確ではありません。例を次に示します:function foo() { console.log(this.a); } var a = 1; var obj = { a: 2, foo }; obj.foo(); // 2 var obj2 = { a: 3, obj }; obj2.obj.foo(); // 2
この例では、foo は obj のメンバーとみなされますこのとき、obj が関数のコンテキストとなり、this は obj を指します。
this.a は obj.a と同等です。オブジェクト プロパティ チェーン呼び出しでは、最後のレイヤーのみが呼び出し位置に影響します。つまり、最後のレイヤーがこの点に影響します。
多くのフロントエンドの友人がインタビュー中にこの質問を見たことがあるかもしれません:
function foo() { console.log(this.a); } var a = 1; var obj = { a: 2, foo }; var bar = obj.foo; bar(); // 1これは暗黙的バインディングに関する最も一般的な問題です。
暗黙的損失: この方法でバインドされた隠し関数は失われます。バインディング オブジェクト
。 bar は obj.foo への参照ですが、実際には foo 関数そのものを指します。bar 関数は独立した関数の呼び出しです。最初の項目を参照してください。このとき、this は window|unknown# を指します。 ##。 古典的なコールバック関数のこのポインティングの問題もあり、これも暗黙的に失われます。 <pre class="brush:php;toolbar:false">function foo() {
console.log(this.a);
}
function doFoo(fn) {
fn();
}
var a = 1;
var obj = {
a: 2,
foo
};
doFoo(obj.foo); // 1</pre>
要約: 暗黙的なバインディングでは、値を割り当てるとき (コールバックは暗黙的な代入です)、暗黙的な損失の問題に特別な注意を払う必要があります。
3. 表示バインディング JavaScript の
関数には
callと
apply という 2 つのメソッドが用意されており、渡される最初のパラメータは次のとおりです。オブジェクトはこれをバインドします。このオブジェクト。プリミティブ値 (文字列、数値、ブール値) が渡された場合、その値はオブジェクト形式 (new String()、new Boolean()、new Number()) に変換されます。 <pre class="brush:php;toolbar:false">function foo() {
console.log(this.a);
}
var obj = {
a: 1
};
foo.call(obj); // 1</pre>
call
と
を使用してこのポイントを明示的に指定できますが、バインディングが失われるという問題は依然として残ります。これは、いわゆる ハード バインディング (バインド関数)
によって解決できるため、ここでは詳しく説明しません。 4. new
最後に紹介したいのは、
を使用してこれのバインディングを変更することです。新しいものを手動で実装した子供にとっては、より明確になるはずです。 . js では new は他の言語の new とはまったく異なります。
新しい実行プロセス:空のオブジェクトの作成
- 関数の実行結果または現在の空のオブジェクトを返します
function Foo(a) { this.a = a; } var bar = new Foo(2); bar.a; // 2
new を使用して関数を呼び出す場合、新しいオブジェクトを構築し、関数呼び出しでこれにバインドします。 - 優先度
最後に、優先度の関係について簡単に説明します: 新しい > 表示バインディング > 暗黙的バインディング > デフォルト バインディング。
推奨学習: 「
JavaScript 基本チュートリアル