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コマンドのファイル上書きとファイル追加の詳細な説明

推薦する

React でカレンダー コンポーネントを構築するためのステップ バイ ステップ ガイド

目次事業背景テクノロジーの活用技術的な問題デザインのアイデア😱 困惑と苦痛に満ちた顔🙄考え始める🌲デ...

k8sとDockerの関係についての簡単な説明

最近、プロジェクトでは kubernetes (以下、k8s と表記、k と s の間には 8 つの...

::before/:before と ::after/:after の使用に関する深い理解

パート1: 基礎1. :active や :hover などの疑似クラスとは異なり、これらはすべて疑...

React Hooks の一般的な使用シナリオ (概要)

目次1. ステートフック1. 基本的な使い方2. 更新3. 合併を実現する4. 遅延初期化状態5. ...

docker-compose を使用して Apollo カスタム環境をデプロイする詳細なチュートリアル

目次アポロ コンフィギュレーション センターとは何ですか?アポロの特徴クライアントアーキテクチャアー...

JavaScript でのモグラ叩きゲームの実装

この記事では、モグラ叩きゲームを実装するためのJavaScriptの具体的なコードを参考までに紹介し...

Vueはechartsに基づいて3次元の縦棒グラフを実装します

3次元縦棒グラフは、正面、右側、上部の3つの部分で構成されています。描画するときは、正面をグラフィッ...

HTML における要素の水平および垂直中央揃えに関する議論

ページをデザインするときには、ログイン ウィンドウを中央に配置するなど、DIV を中央に配置し、ペー...

Zabbixを介してデータベース接続情報といくつかの拡張機能をすばやく取得します

背景アプリケーション システムの数が増え続けると、当初はアラームを発していなかったアクティブ スレッ...

よくあるNginxの設定ミスの例

目次ルートの場所が見つかりませんオフバイスラッシュ安全でない変数の使用スクリプト名$uri を使用す...

Docker で複数の MySQL コンテナを作成して実行する方法の例

1. mysql/mysql-server:latestイメージを使用してMySQLインスタンスを素...

Vue+element+oss はフロントエンドのフラグメントアップロードとブレークポイント再開を実現します

純粋なフロントエンド実装:切片上傳斷點續傳。斷點續傳カットとアップロードに基づいて実装する必要があり...

ウェブページ作成における絶対パスと相対パスの違い

1. 絶対パスまず、ローカル コンピューターでは、ファイルの絶対パスは、当然、ハード ディスク上でフ...

PrometheusはGrafanaディスプレイを使用してMySQLを監視します

目次Prometheusはエクスポーターを介してMySQLを監視し、Grafanaチャートで表示しま...

CSS で div 凹角スタイルを実装するサンプル コード

通常の開発では、凸型の丸い角、つまり border-radius 属性を使用するのが一般的です。凹角...