このコケティッシュな仕組みを考えると、これを理解することは時代を超えたテーマであり、この記事では、この迷惑な妖精を 6 つの部分に分割して釘付けにしようとします。
これはすべてコンテキストに関するものです。
これは、率直に言うと、現在のコンテキストを所有するボスとコンテキスト オブジェクトを見つけることです。
大きなボスは 6 つのレベルに分けられ、レベルが高いほど、最大のボスのみが認識されます。
通常の状況では、最も力の弱いボスが、ブラウザーで使用する場合はウィンドウになります。それは未定義です。
function showThis () { console.log(this) } function showStrictThis () { 'use strict' console.log(this) } showThis() // window showStrictThis() // undefined
第 2 レベルのボスは率直に言います: この関数の前にあるドットを見つけてください。
this を使用する関数が context オブジェクトに属している場合、この context オブジェクトは this にバインドされます。
たとえば、次の例では、boss は returnThis のコンテキスト オブジェクトであるか、returnThis は Boss に属します。
var boss = { name: 'boss', returnThis () { return this } } boss.returnThis() === boss // true
次の例に注意してください。答えを思いつくことができますか?
var boss1 = { name: 'boss1', returnThis () { return this } } var boss2 = { name: 'boss2', returnThis () { return boss1.returnThis() } } var boss3 = { name: 'boss3', returnThis () { var returnThis = boss1.returnThis return returnThis() } } boss1.returnThis() // boss1 boss2.returnThis() // ? boss3.returnThis() // ?
答えはboss1とwindow ああ、当てはまりましたか?
これを使用する関数を見てください。
boss2.returnThisでは、これを使用する関数はboss1.returnThisなので、これはboss1にバインドされています。
boss3.returnThisでは、これを使用する関数はreturnThisなので、これはスペアタイヤにバインドされています。
これをboss2にバインドするにはどうすればよいですか?
var boss1 = { name: 'boss1', returnThis () { return this } } var boss2 = { name: 'boss2', returnThis: boss1.returnThis } boss2.returnThis() //boss2
はい、これを使用する関数が Boss2 に属している限り、可能です。
第 3 レベルのボスは Object.prototype.call と Object.prototype.apply で、パラメーターを通じてこれを指定できます。 (これを直接割り当てることはできないことに注意してください。this = 2 は ReferenceError を報告します。)
function returnThis () { return this } var boss1 = { name: 'boss1' } returnThis() // window returnThis.call(boss1) // boss1 returnThis.apply(boss1) // boss1
第 4 レベルのボスは Object.prototype.bind で、これは新しい関数を通じて永続性を提供するだけではありません。このバインディングは、第 3 レベルのボスのコマンドもカバーします。
function returnThis () { return this } var boss1 = { name: 'boss1'} var boss1returnThis = returnThis.bind(boss1) boss1returnThis() // boss1 var boss2 = { name: 'boss2' } boss1returnThis.call(boss2) // still boss1
これを無視してバインドするのが簡単な場所は新しいです。新しい関数を作成すると、これは自動的に新しいオブジェクトにバインドされ、関数が呼び出されます。これは、bind のバインディングをオーバーライドします。
function showThis () { console.log(this) } showThis() // window new showThis() // showThis var boss1 = { name: 'boss1' } showThis.call(boss1) // boss1 new showThis.call(boss1) // TypeError var boss1showThis = showThis.bind(boss1) boss1showThis() // boss1 new boss1showThis() // showThis
最後の強力なボスは、ES2015 のアロー機能です。アロー関数の this はもはや魅力的なものではなく、Lexical this と呼ばれる現在の語彙スコープに永久に封印されており、コードが実行される前に決定できます。他の偉人はそれをカバーできません。
これの利点は、混乱を引き起こすことを恐れずに、コールバック関数の this が現在のスコープを使用するのに便利であることです。
したがって、アロー関数については、それが作成された場所を見てください。
V8 によって実装された語彙スコープに興味がある場合は、ここを参照してください。
function callback (cb) { cb() } callback(() => { console.log(this) }) // window var boss1 = { name: 'boss1', callback: callback, callback2 () { callback(() => { console.log(this) }) } } boss1.callback(() => { console.log(this) }) // still window boss1.callback2(() => { console.log(this) }) // boss1
次の奇妙な使用法に注意する必要があります:
var returnThis = () => this returnThis() // window new returnThis() // TypeError var boss1 = { name: 'boss1', returnThis () { var func = () => this return func() } } returnThis.call(boss1) // still window var boss1returnThis = returnThis.bind(boss1) boss1returnThis() // still window boss1.returnThis() // boss1 var boss2 = { name: 'boss2', returnThis: boss1.returnThis } boss2.returnThis() // boss2
なぜ最終的に Boss2 なのかわからない場合は、「アロー関数については、それが作成された場所を見てください。」という文を理解してください。
上記は JavaScript の 6 つのハードルの内容です。その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。