「this」キーワードの機能と適切な使用法を理解する
P粉155551728
P粉155551728 2023-10-12 15:50:58
0
2
492

「this」キーワードの機能とその正しい使用方法についての明確な説明を見つけたいと思っています。

奇妙な動作をしているようですが、その理由がまったくわかりません。

thisそれはどのように機能し、いつ使用する必要がありますか?

P粉155551728
P粉155551728

全員に返信 (2)
P粉087951442

thisキーワードは、JavaScript では他の言語と比べて動作が異なります。オブジェクト指向言語では、thisキーワードはクラスの現在のインスタンスを参照します。 JavaScript では、thisの値は、関数の呼び出しコンテキスト (context.function()) と関数の呼び出し元の場所によって決まります。 p>

1.グローバルコンテキストで使用する場合

グローバル コンテキストでthisを使用すると、グローバル オブジェクト (ブラウザのwindow) にバインドされます。 リーリー

グローバル コンテキストで定義された関数内で

thisを使用する場合、その関数は実際にはグローバル コンテキストのメソッドであるため、thisは依然としてグローバル オブジェクトにバインドされます。リーリー 上記の

f1はグローバルオブジェクトのメソッドです。したがって、windowオブジェクト上で次のように呼び出すこともできます:リーリー

2.オブジェクトメソッド内で使用する場合

オブジェクト メソッドで

thisキーワードを使用すると、thisは「直接」囲んでいるオブジェクトにバインドされます。リーリー

上では、「直ちに」という単語を二重引用符で囲みました。これは、オブジェクトが別のオブジェクト内にネストされている場合、

thisは直接の親オブジェクトにバインドされることを示します。リーリー

function をメソッドとしてオブジェクトに明示的に追加した場合でも、上記の規則に従います。つまり、

thisは依然として直接の親オブジェクトを指します。リーリー

3.コンテキストフリー関数を呼び出す場合

コンテキストなしで (つまり、オブジェクト上ではなく) 呼び出される関数内で

thisを使用すると、その関数はグローバル オブジェクト (ブラウザ ## のwindow#) にバインドされます (関数がオブジェクト内で定義されている場合でも)。リーリー

関数を使ってすべてを試してみる

関数を使用して上記の点を試すこともできます。しかし、まだいくつかの違いがあります。

上記では、オブジェクト リテラル表記を使用してオブジェクトにメンバーを追加しました。
    this
  • を使用して関数にメンバーを追加できます。それらを指定します。オブジェクト リテラル表記は、すぐに使用できるオブジェクト インスタンスを作成します。関数の場合、最初に
  • new
  • 演算子を使用して関数のインスタンスを作成する必要がある場合があります。オブジェクト リテラル メソッドでも、ドット演算子を使用して、定義されたオブジェクトにメンバーを明示的に追加できます。これは特定のインスタンスにのみ追加されます。ただし、関数のすべてのインスタンスに反映されるように、変数を関数プロトタイプに追加しました。
  • 以下では、Object と
this

を使用して上記で行ったことをすべて試しましたが、最初にオブジェクトを直接記述する代わりに関数を作成しました。リーリー

4.コンストラクター

内で使用される場合。 関数がコンストラクターとして使用される場合 (つまり、

new

キーワードを使用して呼び出される場合)、関数本体のthisは、構築される新しいオブジェクトを指します。リーリー5.プロトタイプチェーンで定義された関数内で使用される場合

メソッドがオブジェクトのプロトタイプ チェーン上にある場合、メソッド内の

this

は、メソッドがそのオブジェクト上で定義されているかのように、メソッドが呼び出されるオブジェクトを参照します。リーリー

6.内部 call()、apply()、bind() 関数

  • これらのメソッドはすべてFunction.prototypeで定義されています。
  • これらのメソッドを使用すると、関数を一度記述して、それを別のコンテキストで呼び出すことができます。つまり、関数の実行時に使用されるthis値を指定できます。また、元の関数が呼び出されたときに、任意の引数を渡すこともできます。
  • fun.apply(obj1 [, argsArray])obj1thiscode>fun() 内の値に設定します そしてfun()を呼び出し、argsArrayの要素を引数として渡します。
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- obj1 をfun として設定します()thisの値を取得し、arg1、arg2、arg3、...を引数として渡してfun() を呼び出します。
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- 関数funへの参照を返します。、fun のthisobj1にバインドされ、funのパラメータは指定されたパラメータarg1、arg2、arg3 にバインドされます。 、...
  • これで、applycallbindの違いは明らかになるはずです。apply引数を配列のようなオブジェクト、つまり数値lengthプロパティと対応する非負の整数プロパティを持つオブジェクトとして指定できるようにします。また、callを使用すると、関数のパラメーターを直接指定できます。applycallは両方とも、指定されたコンテキストで指定されたパラメーターを使用して関数を直ちに呼び出します。一方、bind は、指定された this 値と引数にバインドされた関数を返すだけです。この返された関数への参照を変数に割り当てることで取得でき、いつでも呼び出すことができます。
リーリー

7. イベント ハンドラー内のthis

  • 関数を要素のイベント ハンドラーに直接割り当てる場合は、イベント ハンドラー関数内でthisを直接使用して、対応する要素を参照します。この直接的な関数の割り当ては、addeventListenerメソッドを使用するか、onclickなどの従来のイベント登録メソッドを介して実行できます。
  • 同様に、要素のイベント属性 (など) 内でthisを直接使用すると、その要素が参照されます。
  • ただし、イベント ハンドラーまたはイベント プロパティ内で呼び出される他の関数を介してthisを間接的に使用すると、グローバル オブジェクトwindowに解決されます。
  • Microsoft のイベント登録モデル メソッドattachEventを使用して関数をイベント ハンドラーにアタッチすると、上記と同じ動作を実現できます。イベント ハンドラーに関数を割り当てる (つまり、要素の関数メソッドを作成する) 代わりに、イベントで関数を呼び出します (事実上、グローバル コンテキストで関数を呼び出します)。

JSFiddle中更好地尝试此操作>.

を使用することをお勧めします。 リーリー

8. ES6 アロー関数のthis

アロー関数では、thisはパブリック変数のように動作します。つまり、その字句スコープから継承されます。アロー関数を定義する関数のthisは、アロー関数のthisになります。

つまり、これは次と同じ動作です:

リーリー

次のコードを参照してください:

リーリー
いいねを押す+0
    P粉156532706

    Thisは、実行コンテキストの属性である JavaScript のキーワードです。主に関数とコンストラクターで使用されます。thisのルールは非常に簡単です (ベスト プラクティスに従う場合)。

    仕様書におけるthisの技術的説明

    ECMAScript StandardDefinitionthis抽象操作 (AOと省略) によるResolveThisBinding:

    グローバル環境レコードモジュール環境レコード、および関数環境レコードには、それぞれ独自の GetThisBinding メソッドがあります。

    GetThisEnvironmentAO は、現在の実行コンテキストの LexicalEnvironment を検索し、を持つ最も近い昇順の環境レコードを ([[OuterEnv]] プロパティを反復処理することにより) 検索します。 this バインディング (つまり、HasThisBinding はtrueを返します)。プロセスは、3 つの環境レコード タイプのいずれかで終了します。

    thisの値は通常、コードがstrict モードであるかどうかによって異なります。

    GetThisBinding の戻り値は、現在の実行コンテキストのthisの値を反映するため、新しい実行コンテキストが確立されるたびに、thisは異なる値に解決されます。これは、現在の実行コンテキストが変更された場合にも発生する可能性があります。次のサブセクションでは、これが発生する可能性のある 5 つのシナリオを示します。

    AST Explorerにコード サンプルを配置して、仕様の詳細に従うことができます。

    ###1。スクリプト内のグローバル実行コンテキスト

    これは、トップレベルで評価されるスクリプトコードです(例:

    で直接)
    スクリプトの初期グローバル実行コンテキスト内で

    thisを評価すると、GetThisBindingが次の手順を実行します。グローバル環境レコードの [[GlobalThisValue]] プロパティは、常に、

    globalThis( Web ウィンドウ、Node.js のglobal、MDN のDocumentation)。 [[GlobalThisValue]] プロパティがどのように生成されるかを学習するには、InitializeHostDefinedRealmの手順に従ってください。###2。moduleのグローバル実行コンテキストモジュールは ECMAScript 2015 で導入されました。

    これは、単に

    ではなく、例えば

    内のモジュールに直接適用されます。

    モジュールの初期グローバル実行コンテキスト内でthisを評価すると、GetThisBindingは次の手順を実行します。

    モジュール内の

    thisの値は、グローバル コンテキストでは常に未定義です。モジュールは暗黙的にstrict モードになっています。###3。

    eval

    コードを入力してください#eval

    呼び出しには、

    directindirectの 2 つのタイプがあります。この区別は ECMAScript 第 5 版から存在しています。直接の

    eval
      呼び出しは通常、
    • eval(...);または(eval)(...## のようになります。 #);(または((eval))(…);
    など)。 1これは directのみです (呼び出し側の式が狭いパターンに準拠している場合)。 2 間接 eval呼び出しには、他の方法で関数参照 eval

  • を呼び出すことが含まれます。eval?.(...),(..., eval)(...),window.eval(...),eval.call(...,...) const aliasEval1 = eval; などを指定します。 window.aliasEval2 = eval;、またはaliasEval1()aliasEval2()code>.それぞれ const を与えます。 originalEval = eval; window.eval = (x) =>originalEval(x);eval()の呼び出しも間接的です。「JavaScript における (1, eval)('this') と eval('this') の違い」に対するchuckj の回答を参照してください。
  • および

    Dmitry Soshnikov の ECMA-262-5 の詳細 – 第 2 章: 間接法を使用する可能性がある状況のための厳密モード(Archived)eval()通話状況。PerformEval

    eval

    コードを実行します。新しい宣言型環境レコードをその LexicalEnvironment として作成します。GetThisEnvironmentはそこからthis値を取得します。その後、evalコードに

    this

    が出現すると、GetThisEnvironmentが呼び出され、その値が返されます。作成される宣言型環境レコードは、

    eval

    呼び出しが直接的か間接的かによって異なります。

    直接評価では、

    this
      値は変更されず、
    • evalという名前の字句スコープから取得されます。間接 eval では、this
    • 値はグローバル オブジェクト (
    • globalThis) です。
    新機能

    についてはどうですか?new Functionevalに似ていますが、コードをすぐに呼び出すのではなく、関数を作成します。thisバインディングは、関数が呼び出されるときを除き、ここではどこにも適用されません。次のサブセクションで説明するように、関数は適切に動作します。###4。関数コード

    を入力してください

    関数を呼び出すときに関数コードを入力します。

    関数を呼び出すための構文には 4 つのカテゴリがあります。

    次の 3 つの実行の場合

    EvaluateCall

    AO:

    3
    • 通常の関数呼び出し 3
    • コンストラクター呼び出し
      • 実際の関数呼び出しは、
      • Call
      AO で発生し、thisValue を使用する呼び出しのコンテキストによって決まります
    • このパラメーターは、呼び出しに関連する長い呼び出しチェーンで渡されます。
    Call

    [[Call]]関数を呼び出すための内部スロット。これにより、PrepareForOrdinaryCallが呼び出され、新しい関数環境レコードが作成されます。さらに、関数環境レコードには [[ThisValue]] フィールドもあります:NewFunctionEnvironmentこの呼び出しでは、関数環境の [[ThisBindingStatus]] プロパティも設定します。

    [[Call]]

    OrdinaryCallBindThisも呼び出します。ここで、適切な

    thisArgument

    は次の内容に基づいて決定されます。

    確認後、新しく作成された関数環境レコードのBindThisValueメソッドが最終的に呼び出され、実際に [[ThisValue]] フィールドがthisArgumentに追加されるように設定されます。

    最後に、このフィールドは関数環境レコードです。GetThisBindingAO は、次の場所からthisの値を取得します。

    繰り返しますが、this値の正確な決定は多くの要因に依存します。これは単なる一般的な概要です。このような技術的な背景を踏まえて、具体的な例をすべて見てみましょう。

    アロー関数

    アロー関数を評価するとき、[[ThisMode]] 内部スロット関数オブジェクトのプロパティは、OrdinaryFunctionCreateで「lexical」に設定されます。 p>

    OrdinaryCallBindThisでは、関数F:

    を受け取ります。

    これは単に、残りのアルゴリズム バインディングthisがスキップされることを意味します。アロー関数は、独自のthis値をバインドしません。

    それでは、アロー関数のthisとは何でしょうか?ResolveThisBindingGetThisEnvironmentを思い出すと、HasThisBinding メソッドは明示的にfalseを返します。

    したがって、私たちは外部環境を繰り返し探します。このプロセスは、thisバインディングを持つ 3 つの環境のいずれかで終了します。

    これは、アロー関数本体のthisがアロー関数の語彙スコープから、つまり (アロー関数と. 関数宣言/式 式: これらは同等/交換可能ですか?):

    関数プロパティ

    通常の関数 (functionmethod) では、this関数呼び出しメソッドによって決まります。

    ここで、これらの「構文のバリエーション」が役に立ちます。

    関数を含むこのオブジェクトについて考えてみましょう:

    リーリー ###または:###リーリー

    次の関数呼び出しでは、func内のthisの値はrefObjになります。1

    • refObj.func()
    • refObj["関数"]()
    • refObj?.func()
    • refObj.func?.()
    • refObj.func``

    呼び出された関数が構文的に基本オブジェクトのプロパティである場合、その基本オブジェクトは呼び出しの「参照」となり、通常の場合はthisの値になります。これについては、上にリンクされている評価手順で説明しています。たとえば、refObj.func()(またはrefObj["func"]()) のCallMemberExpressionは、式refObj.func()全体です。これは、MemberExpressionrefObj.func# で構成されます。 ##パラメーター###### ###()###。さらに、refObj.funcrefObj

    はそれぞれ 3 つの役割を果たします:

    これらはすべて式です、これらはすべて参考資料であり、

      それらはすべて値です。
    • refObj.func
    は呼び出し可能な関数オブジェクトであり、対応する

    参照thisバインディングを決定するために使用されます。オプションのリンクとタグ テンプレートの例は非常によく似ています。基本的に、参照は?.()前、``

    前、または

    ()EvaluateCall 代码>IsPropertyReference

    を使用して、それが構文的にオブジェクトのプロパティであるかどうかを判断します。参照の [[Base]] プロパティを取得しようとします (例:

    refObj.funcに適用される場合はrefObj、適用される場合はfoo.barcode>foo.bar.baz)。プロパティとして記述された場合、GetThisValueはこの [[Base]] プロパティを取得し、それをthis値として使用します。注:Getters / Settersの作業メソッドとメソッド (this

    に関する)。単純なプロパティは、グローバル スコープの

    thisのように、実行コンテキストには影響しません。 リーリー基本参照なし、厳密モード、およびwith

    基本参照のない呼び出しは、通常、属性として呼び出されない関数です。例えば:### リーリーこれは、メソッド を渡すか代入する場合、またはコンマ演算子

    を使用する場合にも発生します。ここで、参照レコードと値の違いが関係します。

    関数

    jについての注意: 仕様によれば、jは参照レコードではなく、関数オブジェクト (値) 自体のみを返すことができることに注意してください。したがって、ベース参照refObj

    が失われます。

    リーリー

    EvaluateCallCallを呼び出します。ここで、thisValue未定義です。これは、OrdinaryCallBindThis(F: 関数オブジェクト;thisArgument:thisValueCallに渡される) では異なります。 # 注: ステップ 5 では、

    thisの実際の値を、厳密モードで提供されるthisArgument(この場合はunknown) に設定します。 「ずさんなモード」では、未定義または nullthisArgumentにより、thisがグローバルthis値になります。

    IsPropertyReference

    falseを返した場合、EvaluateCallは次の手順を実行します。これは未定義ですthisValue

    から取得される可能性があります:

    refEnvWithBaseObject() は、を除き、常にunknownです。 -evaluation" rel="noreferrer">withSymbol.unscopables(Documentation on MDN) もあります。これまでの内容を要約すると:リーリー ###そして:### リーリー

    this

    を計算する場合、

    通常の関数が定義されている位置は問題ではないことに注意してください。

    .call

    .apply

    .bindthisArgとプリミティブOrdinaryCallBindThisステップ 5 のもう 1 つの結果は、(仕様の) ステップ 6.2 とは異なり、「sloppy」モードの元のthis値は

    のみであるということです。オブジェクトにキャストします。

    これを確認するために、this値の別のソースを導入しましょう。thisバインディングをオーバーライドする 3 つのメソッド:4

    Function.prototype.apply(thisArg, argArray)

    Function.prototype.
      {
    • Call,Bind
    • }
    • (thisArg, ...args).bindバインド関数を作成します。その 李>this
    バインディングはすでに

    thisArgに設定されており、再度変更することはできません。.callおよび.applyは関数をすぐに呼び出し、thisthisArg にバインドするように設定します。 ###。

    .call.applyは、指定されたthisArgを使用して、Callに直接マッピングされます。.bindBoundFunctionCreateを使用して、バインドされた関数を作成します。これらには独自の[[Call ]] メソッドがあり、関数オブジェクトの [[BoundThis]] 内部スロットを検索します。

    カスタムthis値の設定例:

    リーリー

    オブジェクトの場合、これは厳密モードでも非厳密モードでも同じです。

    ここで、プリミティブ値を指定してみます:

    リーリー

    非厳密モードでは、プリミティブはオブジェクト ラッパー形式に強制されます。これは、Object("s")またはnew String("s")を呼び出したときに取得するオブジェクト型と同じです。厳密モードでは、プリミティブを使用できます:リーリー

    これらのメソッドを利用するライブラリ (jQuery など) は、ここで選択した DOM 要素に

    thisを設定します:リーリー

    コンストラクター、

    クラスおよびNew

    new演算子を使用して関数がコンストラクターとして呼び出される場合、EvaluateNewConstructを呼び出し、これにより[[Construct]] メソッドが呼び出されます。 ###。関数が基本コンストラクターである場合 (つまり、class extends...{...}ではない)、thisArgumentを次のように設定します。コンストラクターのプロトタイプから作成された新しいオブジェクト。コンストラクターのthisに設定されたプロパティは、最終的に生成されたインスタンス オブジェクトに表示されます。thisは、独自の非プリミティブ値を明示的に返さない限り、暗黙的に返されます。

    classは、ECMAScript 2015 で導入された、コンストラクターを作成する新しい方法です。リーリークラス定義は暗黙的に

    strict モード

    :リーリー #########素晴らしい#########

    new

    動作の例外は、上で説明したclass extends...{... H4>}

    です。派生クラスは、呼び出されてすぐにthis値を設定しません。一連のsuper呼び出しを通じて基本クラスに到達した後でのみ設定します (独自のコンストラクターは暗黙的に発生しません)。関数の場合)。superを呼び出す前にthisを使用することはできません。Callsuper呼び出しの字句スコープ (関数環境レコード) からのthis値を使用してスーパー コンストラクターを呼び出します。

    GetThisValue

    super呼び出しには特別なルールがあります。BindThisValueを使用して、thisをその環境レコードに設定します。リーリー ###5。評価クラスのフィールド

    インスタンス フィールドと静的フィールドは ECMAScript 2022 で導入されました。

    class

    を評価すると、ClassDefinitionEvaluationが実行され、実行中の実行コンテキストが変更されます。各ClassElement:

    フィールドが静的な場合、
      this
    • はクラス自体を参照します。フィールドが静的でない場合、
    • this
    • はインスタンスを参照します。
    • プライベート フィールド (例:
    #x

    ) とメソッドがプライベート環境に追加されます。

    静的ブロック

    は現在、TC39フェーズ3提案です。静的ブロックは静的フィールドやメソッドと同じように機能します。静的ブロック内のthisはクラス自体を参照します。メソッドおよびゲッター/セッターでは、

    this

    は通常の関数プロパティと同じように機能することに注意してください。リーリー


    1

    :(o.f)()o.f()と同等;(f)()は # と同等# #f()この 2ality 記事(アーカイブ済み)。特に括弧付き式を評価する方法を参照してください。2

    :

    MemberExpressionである必要があります。プロパティにすることはできません。[[] の正確な"eval"を持つ必要があります。 ReferencedName]] であり、%eval% 組み込みオブジェクトである必要があります。 em>3

    : 仕様に「

    refを式の評価結果とする。」と記載されている場合は常に、たとえば、MemberExpressionまたはCallExpressionの評価は、これらのアルゴリズムです。これらの一部は参照レコードを生成します。4:this値を指定できるネイティブ メソッドとホスト メソッドが他にもいくつかあります (特に

    Array.prototype.map

    Array .prototype)。 .forEachなどはthisArgを 2 番目の引数として受け入れます。誰もがthisを変更する独自のメソッドを作成できます (例: (func, thisArg) => func.bind(thisArg),(func, thisArg) => func 。 call(thisArg)など。いつものように、MDNは優れたサービス ドキュメントを提供します。お楽しみのために、いくつかの例で理解をテストしてください各コード スニペットについて、次の質問に答えてください:「マークされた行の

    this
    の値は何ですか?なぜですか?」

    .

    答えを表示するには、灰色のボックスをクリックします。

    1. リーリー

      グローバルこれ。マークされた行は、初期のグローバル実行コンテキスト内で評価されます。

    2. リーリー

    いいねを押す+0
      最新のダウンロード
      詳細>
      ウェブエフェクト
      公式サイト
      サイト素材
      フロントエンドテンプレート
      私たちについて 免責事項 Sitemap
      PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!