JS 矢印関数に適さないシナリオは何ですか?

JS 矢印関数に適さないシナリオは何ですか?

概要

長い年月を経て、ES6 は矢印関数やクラスなど、js の使いやすさを新たなレベルに引き上げました。これは素晴らしいことです。

アロー関数は最も価値のある新機能の 1 つであり、そのコンテキストの透明性と短い構文について説明した優れた記事が多数あります。

しかし、すべての取引には2つの側面があります。多くの場合、新しい機能は何らかの混乱をもたらしますが、その混乱の 1 つが矢印関数の誤った使用です。この記事では、矢印関数をバイパスして、古き良き関数式または新しい省略構文を使用する必要があるシナリオをいくつか説明します。また、コードの読みやすさに影響するため、コードを短くするように注意してください。

オブジェクトにメソッドを定義する

JavaScript では、メソッドはオブジェクトのプロパティとして保存される関数です。メソッドが呼び出されると、this はメソッドが属するオブジェクトを参照します。

オブジェクトリテラル

アロー関数は構文が短いので、メソッドの定義に使いたくなります。試してみましょう。

定数計算 = {
  配列: [1, 2, 3],
  合計: () => {
    console.log(this === window); // => true
    this.array.reduce((result, item) => result + item); を返します。
  }
};
console.log(this === window); // => true
// "TypeError: undefined のプロパティ 'reduce' を読み取ることができません" をスローします
計算します。

calculate.sum メソッドは矢印関数を使用して定義されます。 しかし、呼び出されると、this.array が未定義であるため、calculate.sum() は TypeError をスローします。

calculate オブジェクトで sum() メソッドが呼び出されると、コンテキストは引き続き window になります。これは、矢印関数がコンテキストをウィンドウ オブジェクトに構文的にバインドするために発生します。

this.array を実行すると、window.array が実行されることになり、これは未定義になります。

解決策は、正規関数式を使用してメソッドを定義することです。これは呼び出し時に決定され、囲んでいるコンテキストによって決定されません。修正バージョンを見てみましょう。

定数計算 = {  
  配列: [1, 2, 3],
  合計() {
    console.log(this === calculate); // => true
    this.array.reduce((result, item) => result + item); を返します。
  }
};
calculate.sum(); // => 6

sum は通常の関数なので、calculate.sum() を呼び出すと、これは calculate オブジェクトになります。 this.array は配列参照なので、要素の合計は正しく計算されます: 6。

オブジェクトプロトタイプ

プロトタイプ オブジェクトでメソッドを定義する場合にも同じルールが適用されます。矢印関数を使用してsayCatNameメソッドを定義します。これはwindowを指します。

関数 MyCat(名前) {
  this.catName = 名前;
}
MyCat.prototype.sayCatName = () => {
  console.log(this === window); // => true
  this.catName を返します。
};
const cat = new MyCat('Mew');
cat.sayCatName(); // => 未定義

以前の方法を使用して関数式を定義します。

関数 MyCat(名前) {
  this.catName = 名前;
}
MyCat.prototype.sayCatName = 関数() {
  console.log(this === cat); // => true
  this.catName を返します。
};
const cat = new MyCat('Mew');
cat.sayCatName(); // => 'ニャー'

sayCatName の通常関数は、メソッド cat.sayCatName() として呼び出されると、コンテキストを cat オブジェクトに変更します。

動的コンテキストコールバック関数

これは、関数の呼び出し方法に応じてコンテキストを変更できる JS の強力な機能です。通常、コンテキストは呼び出しが行われるターゲット オブジェクトであり、これにより、このオブジェクトに何が起こるかと同じようにコードがより自然になります。

ただし、矢印関数は宣言時にコンテキストを静的にバインドし、動的にすることはできませんが、このアプローチには良い面と悪い面があり、動的バインドが必要になる場合があります。

DOM 要素にイベント リスナーをアタッチすることは、クライアント側プログラミングでは一般的なタスクです。イベントはハンドラー関数をトリガーし、これをターゲット要素として使用します。ここで矢印関数を使用するのは柔軟性が足りません。

次の例では、このようなハンドラーに矢印関数を使用しようとしています。

ボタン = document.getElementById('myButton');
button.addEventListener('click', () => {
  console.log(this === window); // => true
  this.innerhtml = 'ボタンをクリックしました';
});

グローバルコンテキストでは、これはウィンドウを指します。 クリック イベントが発生すると、ブラウザーはボタン コンテキストを使用してハンドラー関数を呼び出そうとしますが、矢印関数は定義済みのコンテキストを変更しません。 this.innerhtml は window.innerHTML と同等であり、意味がありません。

関数式を適用する必要があります。これにより、ターゲット要素に応じてこれを変更できます。

ボタン = document.getElementById('myButton');
button.addEventListener('click', 関数() {
  console.log(this === button); // => true
  this.innerHTML = 'クリックされたボタン';
});

ユーザーがボタンをクリックすると、ハンドラー関数内の this がボタンを指します。したがって、この質問です。 innerHTML = 'Clicked button' は、クリックされた状態を反映するようにボタンのテキストを正しく変更します。

コンストラクタの呼び出し

コンストラクター呼び出し内の this は新しく作成されたオブジェクトです。 new MyFunction() が実行されると、コンストラクター MyFunction のコンテキストは新しいオブジェクトになります: this instanceof MyFunction === true。

矢印関数はコンストラクターとして使用できないことに注意してください。 JavaScript は例外をスローすることでこれを暗黙的に防止します。

いずれにしても、これは新しく作成されたオブジェクトではなく、囲むコンテキストから設定されます。つまり、矢印関数のコンストラクター呼び出しは意味をなさず、曖昧です。

これを実行すると何が起こるか見てみましょう:

const メッセージ = (テキスト) => {
  this.text = テキスト;
};
// "TypeError: メッセージはコンストラクタではありません" をスローします
const helloMessage = 新しいメッセージ('Hello World!');

Message が矢印関数である new Message('Hello World!') を実行すると、Message はコンストラクターとして使用できないため、JavaScript は TypeError エラーをスローします。

上記の例は、関数式を使用して修正できます。これは、コンストラクターを作成する正しい方法です (関数宣言を含む)。

const メッセージ = 関数(テキスト) {
  this.text = テキスト;
};
const helloMessage = 新しいメッセージ('Hello World!');

省略構文

矢印関数には、パラメータ括弧 ()、ブロック中括弧 {} を省略でき、関数本体にステートメントが 1 つしかない場合は return できるという優れた特性があります。これは非常に短い関数を書くのに役立ちます。

原作者の大学のプログラミング教授は学生たちに、C 言語で文字列の長さを計算する最短の関数を書くという興味深い課題を与えました。これは新しい言語を学び、探求する素晴らしい方法です。

しかし、実際のアプリケーションでは、多くの開発者がコードを読みます。 最も短い構文は、メソッドが何を行うかを同僚が即座に理解するのに必ずしも適切であるとは限りません。

ある時点で、ショートカット関数は読みにくくなるため、過度に使用しないようにしてください。例を挙げてみましょう。

const multiply = (a, b) => b === 未定義 ? b => a * b : a * b;
定数倍 = 乗算(2);
ダブル(3); // => 6
乗算(2, 3); // => 6

multiply は、2 つの数値を乗算した結果、または後続の乗算演算のために最初の引数にバインドされたクロージャを返します。

機能は問題なく動作し、短いようです。しかし、最初からそれが何をするのか理解するのは困難でした。

読みやすくするために、矢印関数からオプションの中括弧と return ステートメントを復元するか、通常の関数を使用します。

関数 multiply(a, b) {
  b === 未定義の場合{
    関数(b)を返す{
      a * b を返します。
    }
  }
  a * b を返します。
}
定数倍 = 乗算(2);
ダブル(3); // => 6
乗算(2, 3); // => 6

簡潔さと冗長性のバランスを見つけてコードをより直感的にすることが大切です。

要約する

矢印関数が素晴らしい追加機能であることは間違いありません。正しく使用すると、.bind() の使用や、以前は必要だった場所でのコンテキストのキャプチャが簡単になります。また、コードも簡素化されます。

ある状況では利点となるものが、他の状況では欠点となることもあります。 矢印関数は、動的なコンテキストが必要な場合には使用できません。たとえば、メソッドの定義、コンストラクターを使用したオブジェクトの作成、イベントの処理時に this からターゲットを取得する場合などです。

以上がJSがアロー関数に適さない理由の詳細です。JSについてさらに詳しく知りたい方は、123WORDPRESS.COM内の他の関連記事もぜひご覧ください!

以下もご興味があるかもしれません:
  • より良い JavaScript 条件文と一致条件を書くためのヒント (要約)
  • JSの矢印関数におけるこのポイントの詳細な説明
  • JavaScriptのアロー関数の特徴と通常の関数との違い
  • JavaScript の矢印関数と通常の関数の違いの詳細な説明
  • JavaScript で矢印関数を使用できないシナリオはどれですか
  • JavaScript の条件付きアクセス属性と矢印関数の紹介

<<:  CentOS 7 で MySQL 5.7 をインストールして設定する

>>:  Linuxコマンドのファイル上書きとファイル追加の詳細な説明

推薦する

初心者向けのMySQLデータベースとテーブルDDLの作成と操作の学習

目次1. データベースを操作する1.1 データベースを作成する1.2 データベースをクエリする1.3...

Vueを使用してタイマー機能を実装する

この記事の例では、タイマー機能を実装するためのVueの具体的なコードを参考までに共有しています。具体...

シンプルなカウントダウン効果を実現するJavaScript

この記事の例では、カウントダウン効果を実現するためのJavaScriptの具体的なコードを参考までに...

Prometheus を使用して、MySQL の自動増分主キーの残りの使用可能パーセンテージをカウントします。

最近、本番環境のデータベースがログデータを狂ったように書き込み、主キー値のオーバーフローを引き起こし...

Linux サービス管理の 2 つの方法、service と systemctl の詳細な説明

1.サービスコマンドサービスコマンドは実際には/etc/init.dディレクトリに移動し、関連プログ...

20個のJavaScriptワンラインコードを共有する

目次1. ブラウザのクッキーの値を取得する2. RGBを16進数に変換する3. クリップボードにコピ...

ftp は SSH 経由で Linux にリモート接続します

まず Linux に ssh をインストールします。例として Centos を使用します。ポータル:...

MYSQLデータベーステーブル構造の最適化方法の詳細な説明

この記事では、例を使用して、MYSQL データベース テーブル構造を最適化する方法を説明します。ご参...

高性能ウェブサイトの最適化ガイド

パフォーマンスの黄金律:エンドユーザーの応答時間のわずか 10% ~ 20% が HTML ドキュメ...

CSS プロパティ *-gradient の実用的な価値を探る

まず興味深い性質であるconic-gradientを紹介しましょう。円錐グラデーション!円グラフの作...

MYSQLストアドプロシージャ、つまり一般的な論理知識のポイントの要約

MySQL ストアド プロシージャ1. ストアドプロシージャ構文(フォーマット)を作成する 区切り文...

HTML テーブルタグと関連する改行の問題の詳細な分析

テーブルとは何ですか?テーブルは、データのキャリアである HTML テーブルです。以下は比較的標準的...

リンク内の href=# はどういう意味ですか?

現在のページへのリンク。 -------------------一般的な使用法は次のとおりです。 &...

Dockerにおけるオーバーレイネットワークの詳細な説明

Docker 公式ドキュメントからの翻訳、原文: https://docs.docker.com/n...

formData 形式タイプを使用してファイルをアップロードする Vue の例

Vue では、一般的にフロントエンドとバックエンドを分離したプロジェクトがあり、データ操作を実装する...