JS での矢印関数と this の記述と理解

JS での矢印関数と this の記述と理解

序文

JavaScript は ES6 構文に矢印関数を追加しました。従来の関数と比較すると、矢印関数はより簡潔であるだけでなく、この点でも改善されています。これは JavaScript ではかなり奇妙なことです。多くの記事ではこれについてさまざまな解釈をしています。この記事では、JS における関数と this の関係を明らかにしようとします。

1. JSで関数を書く方法

1. 通常の関数の書き方

ES6 構文より前は、JS の関数は function キーワード、 params パラメータ、および中括弧で囲まれた関数本体で構成されていました。後述するアロー関数と区別するために、まずこのような関数を通常の関数と呼びます。通常の関数は、宣言型と代入型の両方で記述できます。例:

function test(name) { //宣言型の記述 console.log(name)
}
テスト('ジェリー')

let test2 = function(name) { // 割り当ての書き込み console.log(name)
}
test2('トム')

2. 矢印関数の書き方

ES6 の矢印関数の導入により、関数の記述はより簡潔になりましたが、記述する際には特定のルールに従う必要があります。

ルール1: アロー関数は宣言型ではなく代入型でのみ記述できる

例:

const テスト = (名前) => {
 console.log(名前)
}
テスト('ジェリー')

ルール 2: パラメータが 1 つしかない場合は、括弧を追加する必要はありません。パラメータがない場合、またはパラメータが複数ある場合は、括弧を追加する必要があります。

例:

const テスト = 名前 => {
 console.log(名前)
}
テスト('ジェリー')

定数テスト2 = (名前1, 名前2) => {
 console.log(name1 + ' および ' + name2)
}
test2('トム', 'ジェリー')

ルール3: 関数本体が1文だけの場合は中括弧を使う必要はありません

例:

const テスト = 名前 => console.log(名前) 

ルール4: 関数本体に括弧がない場合は、returnを書く必要はありません。矢印関数が戻り値を返すのに役立ちます。

例:

定数追加 = (p1, p2) => p1 + p2
追加(10, 25)

覚えておいてください: 関数本体の中括弧は return キーワードと一緒に使用されます。

上記の例から、矢印関数は通常の関数の括弧と中括弧の両方を簡略化することがわかります。これらの簡略化に加えて、通常の関数に対する矢印関数の最大の最適化は次のとおりです。

2. 通常の関数でこれを理解する

このための矢印関数の最適化について説明する前に、まずこれが何であるか、どのように使用されるかを理解する必要があります。これは、call メソッドを使用して関数を呼び出すときに渡される最初のパラメーターです。関数が呼び出されたときに変更できます。関数が呼び出されない場合、this の値は決定できません。

関数を呼び出すために call メソッドを使用したことがない場合は、上記の定義が明確でない可能性があります。まず関数呼び出しの 2 つの方法を理解する必要があります。

1. 純粋関数呼び出し

最初の方法が最も一般的であり、次に例を示します。

関数テスト(名前) {
 console.log(名前)
 console.log(これ)
}
test('Jerry') //関数を呼び出す

このメソッドは最もよく使用されますが、この関数呼び出しメソッドは単なる省略形です。完全な記述は次のとおりです。

関数テスト(名前) {
 console.log(名前)
 console.log(これ)
}
test.call(未定義、'トム')

上記の関数を呼び出す call メソッドに気づきましたか? call メソッドが受け取る最初のパラメーターはこれであり、ここでは undefined を渡します。それで、定義によれば、関数の実行後に入力された this は未定義になるのでしょうか?あまり。

渡したコンテキストが null または未定義の場合、ウィンドウ オブジェクトがデフォルトのコンテキストになります (厳密モードでのデフォルトのコンテキストは未定義です)。

ここで入力したのは Window オブジェクトです。

2. オブジェクト内の関数の呼び出し

直接例を見てみましょう:

定数オブジェクト = {
 名前: 'ジェリー'、
 挨拶: 関数() {
 console.log(この名前)
 }
}
obj.greet() //最初の呼び出しメソッド obj.greet.call(obj) //2番目の呼び出しメソッド

この例では、最初の呼び出しメソッドは、2 番目の呼び出しメソッドの単なる構文糖衣です。2 番目のメソッドは完全な呼び出しメソッドであり、2 番目のメソッドの強みは、これを手動で指定できることにあります。

これを手動で指定する例:

定数オブジェクト = {
 名前: 'ジェリー'、
 挨拶: 関数() {
 console.log(この名前)
 }
}
obj.greet.call({name: 'Spike'}) //出力はSpike

上記の例から、greet 関数が実行されたときにこれが変更されたことがわかります。

3. コンストラクタ内の this

コンストラクタ内の this は少し特殊です。各コンストラクタは new の後にオブジェクトを返します。このオブジェクトはコンテキストである this です。

例:

関数テスト() {
 this.name = 'トム'
}
p = 新しい Test() とする
console.log(typeof p) //オブジェクト
console.log(p.name) // トム

4. window.setTimeout() および window.setInterval() 内の関数の呼び出し

window.setTimeout() および window.setInterval() 関数内の this はやや特殊です。内部の this はデフォルトで window オブジェクトになります。

簡単にまとめると、完全な関数呼び出し方法は、test.call(context, name) や obj.greet.call(context,name) などの call メソッドを使用することです。context は関数が呼び出されたときのコンテキスト、つまり this ですが、これは call メソッドを通じて変更できます。コンストラクタは少し特殊で、その this は new の後に返されるオブジェクトを直接指します。window.setTimeout() と window.setInterval() は、デフォルトで this をウィンドウ オブジェクトに設定します。

3. 矢印関数でこれを理解する

これについては上でたくさん話しました。これは、関数が call メソッドで呼び出されたときに渡される最初のパラメーターであり、手動で変更できるため、これの値を決定するのは非常に面倒です。しかし、矢印関数の出現はこれを判断するのに役立ちます。

1. 矢印関数の機能1: 外側のthisへのデフォルトのバインディング

前述のとおり、 this の値は call メソッドを使用して変更できますが、 this の値は呼び出し時にのみ決定できます。矢印関数を使用すると、矢印関数はデフォルトで外側の this の値をバインドするため、矢印関数内の this の値は外側の this と同じになります。

矢印関数のない例:

定数オブジェクト = {
	a: 関数() { console.log(this) } 
}
obj.a() //出力はobjオブジェクトです

矢印関数の使用例:

定数オブジェクト = {
 a: () => {
 console.log(これ)
 }
}
obj.a() //出力はウィンドウ

矢印関数を使用する例では、矢印関数はデフォルトで独自の this を使用せず、外側の this と一貫性を保つため、最も外側の this は window オブジェクトになります。

2. 矢印関数の2番目の特徴: 内部で呼び出しメソッドを使用してこれを変更することはできません。

これも簡単に理解できます。関数の this は call メソッドを使用して手動で指定できることを前に説明しました。複雑さを軽減するために、矢印関数では call メソッドを使用して this を指定することはできません。

例:

定数オブジェクト = {
 a: () => {
 console.log(これ)
 }
}
obj.a.call('123') //結果は依然としてウィンドウオブジェクトです

上で、window.setTimeout() 関数のデフォルトの this は window であると述べたため、矢印関数を使用して、その this を外側の this と一致させることもできます。

window.setTimeout() の例:

定数オブジェクト = {
 a: 関数() {
 console.log(これ)
 ウィンドウ.setTimeout(() => { 
  console.log(これ) 
 }, 1000)
 }
}
obj.a.call(obj) //最初の this は obj オブジェクト、2 番目の this も obj オブジェクト

関数 obj.a は矢印関数を使用していないことは誰もが理解していると思います。その理由は、その this が依然として obj であり、setTimeout 内の関数が矢印関数を使用しているため、これも obj である外側の this と一貫性があるからです。setTimeout 内の関数が矢印関数を使用しない場合は、window オブジェクトとして入力する必要があります。

4. 多層オブジェクトネストにおけるこの関数

ここで私が勉強中に遭遇したちょっとした混乱について述べます。矢印関数の this は外側のレイヤーと一致していますが、この外側のレイヤーに複数のレイヤーがある場合、どのレイヤーと一致しているのでしょうか?

直接例を見てみましょう:

定数オブジェクト = {
 a: 関数() { console.log(this) },
 b: {
 	c: 関数() {console.log(this)}
	}
}
obj.a() // obj オブジェクトを出力します。obj.a.call(obj) と同等です。
obj.bc() // obj.b オブジェクトを出力します。これは obj.bccall(obj.b) と同等です。

上記のコードはすべて直感に沿ったものです。次に、obj.bc に対応する関数を矢印関数に置き換えると、結果は次のようになります。

定数オブジェクト = {
 a: 関数() { console.log(this) },
 b: {
 	c: () => {console.log(これ)}
	}
}
obj.a() //矢印関数なしの出力はobjです
obj.bc() // 印刷されるのはウィンドウ オブジェクトです。 !

obj.a を呼び出した後、obj オブジェクトが出力されますが、obj.bc を呼び出した後、obj の代わりに window オブジェクトが出力されます。これは、複数レイヤーのオブジェクトのネストでは、矢印関数の this が最も外側のレイヤーと一致していることを意味します。

上記内容は著者がアロー関数を学ぶ際に整理した知識ポイントです。間違いがあればご指摘・ご訂正をお願いします!これは私が Nuggets について書いた 3 番目の記事です。読んでいただきありがとうございます。

この記事の参照: これの価値は何ですか?一度明確にする

要約する

これで、JS で矢印関数と this を記述して理解する方法に関するこの記事は終了です。より関連性の高い JS 矢印関数と this コンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • JavaScript の基本を詳しく分析: this 関数と矢印関数
  • JavaScriptの矢印関数での詳細な説明
  • JavaScriptの矢印関数の詳細な理解
  • JSの矢印関数におけるこのポイントの詳細な説明

<<:  JavaScriptの詳細な説明 thisキーワード

>>:  js での遅延読み込みとプリロードの具体的な使用法

推薦する

MySQLユーザー削除バグを解決する

著者が MySQL を使用してユーザーを追加していたところ、ユーザー名が間違って記述されていることに...

JavaScript 上級プログラミング: 変数とスコープ

目次1. 元の値と参照値2. インスタンス3. 範囲1. 元の値と参照値6 つの単純なデータ型の値は...

Vueプロジェクトの最適化とパッケージ化の詳細な説明

目次序文1. ルーティングの遅延読み込み1. ルートの遅延読み込みが必要なのはなぜですか? 2. ル...

いくつかのMySQL更新操作のケース分析

目次ケーススタディアカウント残高を更新する直接更新楽観的ロック方式ロックフリーソリューションキューイ...

MySQL データベースのバックアップ プロセスに関する注意事項

今日は、データ バックアップに関連するいくつかの点について調べ、MySQL データ バックアップに関...

LinuxカーネルマクロContainer_Ofの詳細な説明

目次1. 構造体はメモリにどのように保存されますか? 2. container_ofマクロ3. 型4...

ブラウザ(IEシリーズ)を判別するための条件付きコメント

<!--[if IE 6]> IE6 のみが認識可能 <![endif]-->...

WIN10 システムと Docker 内部コンテナ IP 間の通信方法

1. Windows 版の Docker をインストールしたら、Docker クイックスタート ター...

vue3.0 でカルーセル コンポーネントをカプセル化する手順

目次1: カプセル化の考え方2. 包装工程3: ドットインジケーター4: 左と右のインジケーター5:...

React+Ant Design開発環境をセットアップするための実装手順

基礎1. スキャフォールディングを使用してプロジェクトを作成し、開始する1.1 足場を設置する: n...

Dockerコンテナはルーティングを介して直接通信し、ネットワーク通信を実現します。

概要Docker 自体の現在のデフォルト ネットワークについては、単一ホスト上の異なる Docker...

Ubuntu 上の MySQL における中国語文字化け問題の解決方法

問題を見つける最近 Django を学習しているのですが、MySQL データと組み合わせてデータを挿...

MySQL 接続数を設定する方法 (接続数が多すぎる)

mysql使用中に接続数が超過していることが判明しました~~~~ [root@linux-node...

Vue で pdfjs を使用して PDF ファイルをプレビューする方法

目次序文考えるライブラリディレクトリの解析とダウンロード使い方ファイルの場所実際の通話質問要約する序...

mybatis-plusページングパラメータが渡された後、SQLのwhere条件にはページング情報操作の制限がありません

2時間近くかけて、さまざまな方法を試しました。後で、whereでフィルタリングした後のデータ量が1ペ...