これで、apply、call、bindの違いは明らかになるはずです。apply引数を配列のようなオブジェクト、つまり数値lengthプロパティと対応する非負の整数プロパティを持つオブジェクトとして指定できるようにします。また、callを使用すると、関数のパラメーターを直接指定できます。applyとcallは両方とも、指定されたコンテキストで指定されたパラメーターを使用して関数を直ちに呼び出します。一方、bind は、指定された this 値と引数にバインドされた関数を返すだけです。この返された関数への参照を変数に割り当てることで取得でき、いつでも呼び出すことができます。
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])
obj1
をthis
code>fun() 内の値に設定します そしてfun()
を呼び出し、argsArray
の要素を引数として渡します。fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- obj1 をfun として設定します()
this
の値を取得し、arg1、arg2、arg3、...
を引数として渡してfun() を呼び出します。
fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- 関数funへの参照を返します。
、fun のthis
はobj1
にバインドされ、fun
のパラメータは指定されたパラメータarg1、arg2、arg3 にバインドされます。 、...
。apply
、call
、bind
の違いは明らかになるはずです。apply
引数を配列のようなオブジェクト、つまり数値length
プロパティと対応する非負の整数プロパティを持つオブジェクトとして指定できるようにします。また、call
を使用すると、関数のパラメーターを直接指定できます。apply
とcall
は両方とも、指定されたコンテキストで指定されたパラメーターを使用して関数を直ちに呼び出します。一方、bind は、指定された this 値と引数にバインドされた関数を返すだけです。この返された関数への参照を変数に割り当てることで取得でき、いつでも呼び出すことができます。7. イベント ハンドラー内の
this
this
を直接使用して、対応する要素を参照します。この直接的な関数の割り当ては、addeventListener
メソッドを使用するか、onclick
などの従来のイベント登録メソッドを介して実行できます。など) 内で
this
を直接使用すると、その要素が参照されます。this
を間接的に使用すると、グローバル オブジェクトwindow
に解決されます。attachEvent
を使用して関数をイベント ハンドラーにアタッチすると、上記と同じ動作を実現できます。イベント ハンドラーに関数を割り当てる (つまり、要素の関数メソッドを作成する) 代わりに、イベントで関数を呼び出します (事実上、グローバル コンテキストで関数を呼び出します)。JSFiddle中更好地尝试此操作>.
を使用することをお勧めします。 リーリー8. ES6 アロー関数の
this
アロー関数では、
this
はパブリック変数のように動作します。つまり、その字句スコープから継承されます。アロー関数を定義する関数のthis
は、アロー関数のthis
になります。つまり、これは次と同じ動作です:
リーリー次のコードを参照してください:
リーリーThis
は、実行コンテキストの属性である JavaScript のキーワードです。主に関数とコンストラクターで使用されます。this
のルールは非常に簡単です (ベスト プラクティスに従う場合)。仕様書における
this
の技術的説明ECMAScript StandardDefinition
this
抽象操作 (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
evalの値は、グローバル コンテキストでは常に
未定義です。モジュールは暗黙的に
strict モードになっています。###3。コードを入力してください#eval
呼び出しには、direct
evalと
indirectの 2 つのタイプがあります。この区別は ECMAScript 第 5 版から存在しています。直接の呼び出しは通常、- eval(
...
);または
(eval)(...## のようになります。 #);
(または((eval))(
…);1
これはdirect
のみです (呼び出し側の式が狭いパターンに準拠している場合)。 2 間接 eval呼び出しには、他の方法で関数参照 evaleval?.(
...)
,(
..., 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()通話状況。
evalPerformEval
コードを実行します。新しい宣言型環境レコードをその LexicalEnvironment として作成します。
thisGetThisEnvironment
はそこからthis値を取得します。その後、eval
コードにが出現すると、
evalGetThisEnvironment
が呼び出され、その値が返されます。作成される宣言型環境レコードは、
呼び出しが直接的か間接的かによって異なります。
直接評価では、
this値は変更されず、- eval
値はグローバル オブジェクト (
- globalThis
新機能という名前の字句スコープから取得されます。
間接 eval では、
this) です。
についてはどうですか?—
を入力してくださいnew Functionは
eval
に似ていますが、コードをすぐに呼び出すのではなく、関数を作成します。thisバインディングは、関数が呼び出されるときを除き、ここではどこにも適用されません。次のサブセクションで説明するように、関数は適切に動作します。
###4。関数コード関数を呼び出すときに関数コードを入力します。
関数を呼び出すための構文には 4 つのカテゴリがあります。次の 3 つの実行の場合
EvaluateCallAO:
3[[Call]]関数を呼び出すための内部スロット。これにより、PrepareForOrdinaryCallが呼び出され、新しい関数環境レコードが作成されます。さらに、関数環境レコードには [[ThisValue]] フィールドもあります:NewFunctionEnvironmentこの呼び出しでは、関数環境の [[ThisBindingStatus]] プロパティも設定します。
[[Call]]はOrdinaryCallBindThisも呼び出します。ここで、適切な
thisArgumentは次の内容に基づいて決定されます。
確認後、新しく作成された関数環境レコードのBindThisValueメソッドが最終的に呼び出され、実際に [[ThisValue]] フィールドがthisArgumentに追加されるように設定されます。
最後に、このフィールドは関数環境レコードです。GetThisBindingAO は、次の場所から
this
の値を取得します。繰り返しますが、this値の正確な決定は多くの要因に依存します。これは単なる一般的な概要です。このような技術的な背景を踏まえて、具体的な例をすべて見てみましょう。
アロー関数
アロー関数を評価するとき、[[ThisMode]] 内部スロット関数オブジェクトのプロパティは、OrdinaryFunctionCreateで「lexical」に設定されます。 p>
OrdinaryCallBindThisでは、関数F:
を受け取ります。これは単に、残りのアルゴリズム バインディングthisがスキップされることを意味します。アロー関数は、独自のthis値をバインドしません。
それでは、アロー関数の
this
とは何でしょうか?ResolveThisBindingとGetThisEnvironmentを思い出すと、HasThisBinding メソッドは明示的にfalseを返します。したがって、私たちは外部環境を繰り返し探します。このプロセスは、thisバインディングを持つ 3 つの環境のいずれかで終了します。
これは、アロー関数本体の
this
がアロー関数の語彙スコープから、つまり (アロー関数と. 関数宣言/式 式: これらは同等/交換可能ですか?):関数プロパティ
通常の関数 (
function
、method) では、this
は関数呼び出しメソッドによって決まります。ここで、これらの「構文のバリエーション」が役に立ちます。
関数を含むこのオブジェクトについて考えてみましょう:
リーリー ###または:###リーリー次の関数呼び出しでは、
func
内のthis
の値はrefObj
になります。1refObj.func()
refObj["関数"]()
refObj?.func()
refObj.func?.()
refObj.func``
呼び出された関数が構文的に基本オブジェクトのプロパティである場合、その基本オブジェクトは呼び出しの「参照」となり、通常の場合は
はそれぞれ 3 つの役割を果たします:this
の値になります。これについては、上にリンクされている評価手順で説明しています。たとえば、refObj.func()
(またはrefObj["func"]()
) のCallMemberExpressionは、式refObj.func()
全体です。これは、MemberExpressionrefObj.func
と# で構成されます。 ##パラメーター###### ###()###。さらに、refObj.funcと
refObjこれらはすべて式です、
これらはすべて参考資料であり、
それらはすべて値です。- refObj.func
値
は呼び出し可能な関数オブジェクトであり、対応する参照
前、またはは
thisバインディングを決定するために使用されます。オプションのリンクとタグ テンプレートの例は非常によく似ています。基本的に、参照は?.()前、
``()
を使用して、それが構文的にオブジェクトのプロパティであるかどうかを判断します。参照の [[Base]] プロパティを取得しようとします (例:。
EvaluateCall 代码>IsPropertyReference
refObj.funcに適用される場合はrefObj、適用される場合はfoo.bar
に関する)。単純なプロパティは、グローバル スコープのcode>
foo.bar.baz)。プロパティとして記述された場合、
GetThisValueはこの [[Base]] プロパティを取得し、それを
this値として使用します。
注:Getters / Settersの作業メソッドとメソッド (thisthisのように、実行コンテキストには影響しません。 リーリー基本参照なし、厳密モード、および
with
基本参照のない呼び出しは、通常、属性として呼び出されない関数です。例えば:### リーリーこれは、
を使用する場合にも発生します。ここで、参照レコードと値の違いが関係します。 関数メソッド を渡すか代入する場合、または
コンマ演算子jについての注意: 仕様によれば、jは参照レコードではなく、関数オブジェクト (値) 自体のみを返すことができることに注意してください。したがって、ベース参照refObj
が失われます。リーリー
EvaluateCallCallを呼び出します。ここで、thisValueは未定義です。これは、OrdinaryCallBindThis(F: 関数オブジェクト;thisArgument:thisValueがCallに渡される) では異なります。 # 注: ステップ 5 では、
this
IsPropertyReferenceの実際の値を、厳密モードで提供される
thisArgument(この場合はunknown) に設定します。 「ずさんなモード」では、未定義または null
thisArgumentにより、thisがグローバル
this値になります。がfalseを返した場合、EvaluateCallは次の手順を実行します。これは未定義ですthisValue
から取得される可能性があります:refEnv。WithBaseObject() は、を除き、常にunknownです。 -evaluation" rel="noreferrer">withSymbol.unscopables
this(Documentation on MDN) もあります。
これまでの内容を要約すると:
リーリー ###そして:### リーリーを計算する場合、
通常の関数が定義されている位置は問題ではないことに注意してください。
.apply.call
、、
のみであるということです。オブジェクトにキャストします。.bind、
thisArg
とプリミティブOrdinaryCallBindThis
ステップ 5 のもう 1 つの結果は、(仕様の) ステップ 6.2 とは異なり、「sloppy」モードの元のthis値はこれを確認するために、this値の別のソースを導入しましょう。thisバインディングをオーバーライドする 3 つのメソッド:4
Function.prototype.apply(thisArg, argArray)
Function.prototype.{- Call
}
- (thisArg, ...args)
バインディングはすでに,
Bind.bind
バインド関数を作成します。その 李>this
thisArgに設定されており、再度変更することはできません。
.callおよび.applyは関数をすぐに呼び出し、
this
をthisArg にバインドするように設定します。 ###。.call
と.apply
は、指定されたthisArgを使用して、Callに直接マッピングされます。.bind
BoundFunctionCreateを使用して、バインドされた関数を作成します。これらには独自の[[Call ]] メソッドがあり、関数オブジェクトの [[BoundThis]] 内部スロットを検索します。カスタムthis値の設定例:
リーリーオブジェクトの場合、これは厳密モードでも非厳密モードでも同じです。
ここで、プリミティブ値を指定してみます:
リーリー非厳密モードでは、プリミティブはオブジェクト ラッパー形式に強制されます。これは、
これらのメソッドを利用するライブラリ (jQuery など) は、ここで選択した DOM 要素にObject("s")
またはnew String("s")
を呼び出したときに取得するオブジェクト型と同じです。厳密モードでは、プリミティブを使用できます:リーリーthis
コンストラクター、を設定します:
リーリークラスおよびNew
new
演算子を使用して関数がコンストラクターとして呼び出される場合、
EvaluateNewはConstructを呼び出し、これにより[[Construct]] メソッドが呼び出されます。 ###。関数が基本コンストラクターである場合 (つまり、class extends...{
...}
ではない)、thisArgument
を次のように設定します。コンストラクターのプロトタイプから作成された新しいオブジェクト。コンストラクターのthisに設定されたプロパティは、最終的に生成されたインスタンス オブジェクトに表示されます。this
は、独自の非プリミティブ値を明示的に返さない限り、暗黙的に返されます。class
strict モードは、ECMAScript 2015 で導入された、コンストラクターを作成する新しい方法です。
リーリークラス定義は暗黙的に:リーリー #########素晴らしい#########
new動作の例外は、上で説明したclass extends
...
{... H4>}です。派生クラスは、呼び出されてすぐに
GetThisValuethis
値を設定しません。一連のsuper
呼び出しを通じて基本クラスに到達した後でのみ設定します (独自のコンストラクターは暗黙的に発生しません)。関数
の場合)。super
を呼び出す前にthisを使用することはできません。Call
super
呼び出しの字句スコープ (関数環境レコード) からの
this
値を使用してスーパー コンストラクターを呼び出します。super
呼び出しには特別なルールがあります。
BindThisValueを使用して、thisをその環境レコードに設定します。リーリー ###5。評価クラスのフィールドインスタンス フィールドと静的フィールドは ECMAScript 2022 で導入されました。class
を評価すると、
フィールドが静的な場合、ClassDefinitionEvaluation
が実行され、実行中の実行コンテキストが変更されます。各ClassElement:this- はクラス自体を参照します。
this
- はインスタンスを参照します。
プライベート フィールド (例:
#xフィールドが静的でない場合、
) とメソッドがプライベート環境に追加されます。
静的ブロックは現在、TC39フェーズ3提案です。静的ブロックは静的フィールドやメソッドと同じように機能します。静的ブロック内のthisはクラス自体を参照します。
thisメソッドおよびゲッター/セッターでは、
は通常の関数プロパティと同じように機能することに注意してください。
リーリー
1
:(o.f)()は
:o.f()
と同等;(f)()
は # と同等# #f()。
この 2ality 記事(
アーカイブ済み)。特に括弧付き式を評価する方法を参照してください。2MemberExpressionである必要があります。プロパティにすることはできません。[[] の正確な"eval"を持つ必要があります。 ReferencedName]] であり、%eval% 組み込みオブジェクトである必要があります。 em>3
: 仕様に「refを式の評価結果とする。」と記載されている場合は常に、たとえば、MemberExpressionまたはCallExpressionの評価は、これらのアルゴリズムです。これらの一部は参照レコードを生成します。4:this値を指定できるネイティブ メソッドとホスト メソッドが他にもいくつかあります (特に
Array.prototype.map、Array .prototype)。 .forEachなどはthisArgを 2 番目の引数として受け入れます。誰もが
thisthis
を変更する独自のメソッドを作成できます (例: (func, thisArg) => func.bind(thisArg),(func, thisArg) => func 。 call(thisArg)など。いつものように、MDN
は優れたサービス ドキュメントを提供します。お楽しみのために、いくつかの例で理解をテストしてください
各コード スニペットについて、次の質問に答えてください:「マークされた行のの値は何ですか?なぜですか?」
.
答えを表示するには、灰色のボックスをクリックします。