これを理解するおそらく、他のオブジェクト指向プログラミング言語でも まず、ECMAScript 標準仕様におけるこの定義を見てみましょう。
次に、MDN の定義を見てみましょう。
さて、上記の 2 行を理解できる場合は、読み続ける必要はありません。おめでとうございます! …そうは思いません。少なくともこの2行だけを見てもまだ分かりません。 例を見てみましょう: var getGender = 関数() { people1.gender を返します。 }; var 人1 = { 性別: '女性'、 性別を取得: 性別を取得 }; var 人々2 = { 性別: '男性'、 性別を取得: 性別を取得 }; console.log(people1.getGender()); // 女性 console.log(people2.getGender()); // 女性 何ですか? people2 はなぜ性別を変えたのですか? これは私が望んでいる結果ではありません。なぜですか? したがって、 var getGender = 関数() { this.gender を返します。 }; この時点で、 先ほど述べた点に戻ると、この例から、 これで、最初の重要なポイントがわかりました。**this は実際には関数が呼び出されたときにバインドされ、それが指すものは関数の呼び出し方法によって完全に異なります。 **これをどう区別するのでしょうか? これは誰ですか上記の例を読んでも、まだ混乱しているように感じますか?次に、さまざまな呼び出し方法がこの値に与える影響を見てみましょう。 ケース1: グローバルオブジェクトと通常の関数の呼び出しグローバル環境では、これはグローバル オブジェクトを指し、ブラウザーではウィンドウ オブジェクトを指します。次の例では、厳密モードであるかどうかに関係なく、これはグローバル オブジェクトを参照します。 変数x = 1 コンソールログ(this.x) // 1 console.log(this.x === x) // 真 console.log(this === window) // true 非厳密モードでグローバル環境で通常の関数が呼び出された場合、通常の関数内の this もグローバル オブジェクトを参照します。厳密モードでは、 this は未定義になります。 ES5 では、JavaScript をより制限の厳しい環境で実行するための厳密モードが追加されました。セキュリティ リスクを排除するために、厳密モードでは this キーワードがグローバル オブジェクトを指すことが禁止されます。 変数x = 1 関数fn() { console.log(this); // ウィンドウのグローバルオブジェクト console.log(this.x); // 1 } 関数fn(); 厳密モードを使用した後: "use strict" // 厳密モードを使用する var x = 1 関数fn() { console.log(this); // 未定義 console.log(this.x); // this は未定義なので、「未定義のプロパティ 'x' を読み取れません」と報告します } 関数fn(); ケース2: オブジェクトメソッドとして呼び出すオブジェクト内の値がプリミティブ型 (たとえば、文字列、数値、ブール値) である場合、この新しく作成されたものを「プロパティ」と呼びます。また、オブジェクト内の値が関数である場合、この新しく作成されたものを「メソッド」と呼びます。 関数がオブジェクトのメソッドであり、オブジェクトのメソッドとして呼び出される場合、関数内の this は親オブジェクトを指します。 変数x = 1 var obj = { x: 2, 関数: 関数() { console.log(これを); コンソールにログ出力します。 } } obj.fn() // obj.fn() は結果を出力します。 // オブジェクト {x: 2, fn: 関数} // 2 var a = obj.fn () // a() は結果を出力します: // ウィンドウグローバルオブジェクト // 1 上記の例では、obj.fn() を直接実行しています。関数の親オブジェクトは obj なので、this は obj を指し、this.x の値は 2 です。次に、最初に fn メソッドを変数 a に割り当てます。a はグローバル環境で実行されるので、this はグローバル オブジェクト Window を指し、this.x の値は 1 です。 別の例を見てみましょう。関数がネストされた複数のオブジェクトによって呼び出された場合、これは何を指すのでしょうか? 変数x = 1 var obj = { x: 2, 年: { x: 3, 関数: 関数() { console.log(this); // オブジェクト {x: 3, fn: function} console.log(this.x); // 3 } } } obj.y.fn(); なぜ結果が 2 ではないのでしょうか? この場合、1 つの文を覚えておいてください。これは常に、関数を直接呼び出す親オブジェクト、つまり y を指します。上記の例では、実際には次のコードが実行されます。 var y = { x: 3, 関数: 関数() { console.log(this); // オブジェクト {x: 3, fn: function} console.log(this.x); // 3 } } 変数x = 1 var obj = { x: 2, y: y } obj.y.fn(); オブジェクトはネストすることができ、関数も同様にネストできます。関数がネストされると、これは変わりますか?次のコードでこれを調べてみましょう。 var obj = { y: 関数() { console.log(this === obj); // 真 console.log(this); // オブジェクト {y: function} 関数fn(); 関数fn() { console.log(this === obj); // 偽 console.log(this); // ウィンドウのグローバル オブジェクト} } } obj.y(); 関数 y では、this はそれを呼び出す親オブジェクト obj を指しており、これは問題ありません。しかし、ネストされた関数 fn では、これは obj を指しません。ネストされた関数は、それを呼び出す関数から this を継承しません。ネストされた関数が関数として呼び出されると、その this 値は非厳密モードではグローバル オブジェクトを指し、厳密モードでは未定義になります。したがって、上記の例では実際には次のコードが実行されます。 関数fn() { console.log(this === obj); // 偽 console.log(this); // ウィンドウのグローバル オブジェクト} var obj = { y: 関数() { console.log(this === obj); // 真 console.log(this); // オブジェクト {y: function} 関数fn(); } } obj.y(); ケース3: コンストラクターとして呼び出されるnew キーワードを使用して、コンストラクターを通じてインスタンス オブジェクトを生成できます。この時点で、 this は新しいオブジェクトを参照します。 var x = 1; 関数Fn() { 2 を 0 にします。 console.log(this); // 関数 {x: 2} } var obj = new Fn(); // Fn(..) 呼び出しで obj をこれにバインドします console.log(obj.x) // 2 変数x = 1 関数Fn() { これ.x = 2 戻る { ×: 3 } } var a = 新しいFn() コンソール.log(ax) // 3 Fn() はオブジェクト (参照型) を返すため、これは返されたオブジェクトを指します。戻り値が非参照型の場合はどうなりますか? 変数x = 1 関数Fn() { これ.x = 2 戻る 3 } var a = 新しいFn() コンソールログ(ax) // 2 ケース4: call メソッド呼び出しと apply メソッド呼び出しこれが参照するものを変更する場合は、 call または apply メソッドを使用できます。最初のパラメータは、関数の実行時に var x = 1; var obj = { ×: 2 } 関数fn() { console.log(これを); コンソールにログ出力します。 } fn.call(オブジェクト) // オブジェクト {x: 2} // 2 fn.apply(オブジェクト) // オブジェクト {x: 2} // 2 fn.call() // ウィンドウグローバルオブジェクト // 1 fn.apply(null) // ウィンドウグローバルオブジェクト // 1 fn.call(未定義) // ウィンドウグローバルオブジェクト // 1 call と apply を使用する場合、 this に渡される値がオブジェクトでない場合、JavaScript は関連するコンストラクターを使用してそれをオブジェクトに変換します。たとえば、数値型が渡されると、 関数fn() { console.log(Object.prototype.toString.call(this)) } fn.call('love') // [オブジェクト文字列] fn.apply(1) // [オブジェクト番号] fn.call(true) // [オブジェクト ブール値] call と apply の違いは、call の 2 番目以降のパラメータがパラメータ リストであるのに対し、apply の 2 番目のパラメータは配列である点です。パラメータ リストとパラメータ配列はどちらも関数への引数として実行されます。 変数x = 1 var obj = { ×: 2 } 関数Sum(y, z) { コンソールログ(this.x + y + z) } Sum.call(obj, 3, 4) // 9 合計を適用(obj、[3, 4]) // 9 ケース5: バインドメソッド呼び出しf.bind(someObject) を呼び出すと、 f と同じ本体とスコープを持つ関数が作成されますが、この新しい関数では、関数がどのように呼び出されたかに関係なく、新しい関数の this は、 bind によって渡された最初の引数を永続的にポイントします。 変数x = 1 var obj1 = { ×: 2 }; var obj2 = { ×: 3 }; 関数fn() { console.log(これを); コンソールにログ出力します。 }; var a = fn.bind(obj1); var b = a.bind(obj2); 関数fn(); // ウィンドウグローバルオブジェクト // 1 (); // オブジェクト {x: 2} // 2 関数b(); // オブジェクト {x: 2} // 2 a.call(obj2); // オブジェクト {x: 2} // 2 上記の例では、this ポインターを関数 a に再割り当てしようとしていますが、このポインターは最初の bind によって渡されたオブジェクトを依然として指しています。call メソッドまたは apply メソッドを使用しても、この事実は変更できません。つまり、このポインターは、bind によって渡された最初のパラメーターを永続的に指し続けます。 ケース6: thisは矢印関数で指しているES6 以降ではアロー関数が追加されていることも注目に値します。MDN のアロー関数の説明を見てみましょう。
ここでは、矢印関数には独自の var obj = { y: 関数() { console.log(this === obj); // 真 console.log(this); // オブジェクト {y: function} var fn = () => { console.log(this === obj); // 真 console.log(this); // オブジェクト {y: function} } 関数fn(); } } obj.y() 通常の関数と異なり、矢印関数内の this は obj を指しています。これは、前の層の関数から this を継承しているためです。矢印関数は this の方向を修正していることがわかります。したがって、矢印関数の this は呼び出されたときに決定されるのではなく、定義されているときのオブジェクトがその this になります。 つまり、矢印関数の this は、外側のレイヤーに関数があるかどうかによって決まります。外側のレイヤーに関数がある場合、外側の関数の this は内側の矢印関数の this になります。外側のレイヤーに関数がない場合、 this は window になります。 var obj = { y: () => { console.log(this === obj); // 偽 console.log(this); // ウィンドウのグローバルオブジェクト var fn = () => { console.log(this === obj); // 偽 console.log(this); // ウィンドウのグローバル オブジェクト} 関数fn(); } } obj.y() 上記の例では、矢印関数が 2 つありますが、これは実際には最も外側の矢印関数に依存します。obj は関数ではなくオブジェクトであるため、これは Window グローバル オブジェクトを指します。 bind と同様に、矢印関数も非常に「頑固」です。call や apply を通じて this の方向を変更することはできません。つまり、渡された最初のパラメータは無視されます。 変数x = 1 var obj = { ×: 2 } var a = () => { コンソールログ(this.x) console.log(これ) } a.call(オブジェクト) // 1 // ウィンドウのグローバルオブジェクト a.apply(obj) // 1 // ウィンドウのグローバルオブジェクト 上記の説明は文字が多すぎて少し味気ないかもしれませんので、次のフローチャートを見てみましょう。この図は非常によくまとめられていると思います。図のプロセスは単一のルールにのみ適用されます。 まとめこの記事では、これが指すいくつかの状況を紹介します。動作環境や呼び出し方法によって、これが影響を受けます。一般に、関数の this の参照は、現在関数を呼び出しているオブジェクト、つまり実行時のオブジェクトに依存します。このセクションでは、以下の内容を習得する必要があります。
これで、JavaScript ブレークスルー シリーズの「これとは何か」に関する記事は終了です。JavaScript に関するこのコンテンツの詳細については、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
PS: 最近、nginx を詳細に紹介している <<High-Performance ...
目次JavaScriptでは、通常、次のコードのようにクラスを簡単に定義できます。 var サンプル...
目次変換前:変換後: 0x0の基本0x1 「固定高さ」の仮想リストを実装する原理:最適化: 0x2 ...
MySQLは独立した書き込み分離を設定します。コードに次のものを書くと問題が発生する可能性があります...
CS: ... 1. <link type="text/css" href...
1: nginxサーバーソリューション、.conf構成ファイルを変更する解決策は2つある1: 位置 ...
作成されたタブラベルがページの表示領域を超えると、タブラベルの距離だけ自動的にスクロールされます。ま...
目次導入始めるReact Nativeゲームエンジンの簡単な紹介React Nativeでスネークゲ...
目次序文アドバンテージ:欠点: 1. レスポンシブな使用効果2. ステータスが同期されていないRea...
問題/障害/シナリオ/要件Eve-ng の仮想マシン OVA のハードディスクは 38G しかないた...
RocketMQ イメージを検索するには、Docker の hub.docker.com で検索する...
この記事では、次のように、誰にでも共有できる左右幅固定のミドルアダプティブ HTML レイアウトソリ...
序文現在、プロジェクトでは、Axios ライブラリが HTTP インターフェース リクエストによく使...
docker における実行と開始の違いDocker run はミラーイメージを指定します。そしてdo...
CentOS に Docker をインストールするには、オペレーティング システムが CentOS ...