検索

アロー関数を理解する

Jun 16, 2020 am 09:41 AM
js

私は以前、アロー関数についてはすでによく理解していると感じていましたが、再びだまされることはありえないと感じていました。しかし、数日前に非常に奇妙な問題に遭遇し、長い間悩んだ結果、それはアロー機能による落とし穴であることがわかりました。したがって、次の記事があります~

問題の説明

たとえば、基本クラス Animal があり、これには基本メソッドsayNameがあります。それを継承する後続の各サブクラスは、その身元を証明するために、sayName メソッドを実装する必要があります。基本クラス コードの実装は非常に単純です:

class Animal {
	sayName = () => {
		throw new Error('你应该自己实现这个方法');
  }
}

そこで、Animal 基本クラスから継承して Pig サブクラスを実装する必要があります。実装も非常に単純です:

class Pig extends Animal {
	sayName() {
		console.log('I am a Pig');
	}
}

とてもシンプルですか?落とし穴はどこにありますか?ただし、実際に実行してみると、結果が期待どおりではないことがわかります。正確に何が間違っていたのでしょうか?なぜこの短い数行のコードでエラーが報告されるのでしょうか?

問題を発見するアロー関数を理解する

何度も試行錯誤した結果、最終的にそれがアロー関数の落とし穴であることがわかりました。この問題を解決するには、Animal 基本クラスのsayName を通常の関数に変更するか、Pig サブクラスのsayName をアロー関数に変更するだけで済みます。では、アロー関数では一体何が起こっているのでしょうか?

これを書いていて、かつてこの質問について面接官からインタビューを受けたことを突然思い出しました!その際、インタビュアーは、クラスの通常の関数であるアロー関数と、クラスのコンストラクタ内のバインド関数の違いについて質問しました。そのときは答えは明白で論理的でしたが、相続となるとすべてがひっくり返りました。上記の質問に答えるために、まず面接の質問に答えましょう。

アロー関数、通常の関数、コンストラクターのバインド関数の違いは何ですか?

この問題をより直感的に理解するには、次のコードを使用できます。 babel のコンパイル結果と違いを確認したほうがよいでしょう。

最初に、簡単なコードを入力します

class A {
  	constructor() {
		this.b = this.b.bind(this);    	
    }
  
    a() {
    	console.log('a');
    }
	  b() {
    	console.log('b')
    }
    c = () => {
    	console.log('c')
    }
}

babel がコンパイルされてどのようなものになるかを見てみましょう:

"use strict";

function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } }

function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

var A = /*#__PURE__*/function () {
  function A() {
    _classCallCheck(this, A);

    _defineProperty(this, "c", function () {
      console.log(&#39;c&#39;);
    });

    this.b = this.b.bind(this);
  }

  _createClass(A, [{
    key: "a",
    value: function a() {
      console.log(&#39;a&#39;);
    }
  }, {
    key: "b",
    value: function b() {
      console.log(&#39;b&#39;);
    }
  }]);

  return A;
}();

コンパイルされたコードのほとんどは補助関数であり、確認できるのは一部だけです重要なポイントの説明:

var A = /*#__PURE__*/function () {
  function A() {
    _classCallCheck(this, A);

    _defineProperty(this, "c", function () {
      console.log(&#39;c&#39;);
    });

    this.b = this.b.bind(this);
  }

  _createClass(A, [{
    key: "a",
    value: function a() {
      console.log(&#39;a&#39;);
    }
  }, {
    key: "b",
    value: function b() {
      console.log(&#39;b&#39;);
    }
  }]);

  return A;
}();

コンパイル結果から、相互の違いがわかります:

通常の関数: babel がコンパイルされた後、次の場所に配置されます。関数のプロトタイプ

  • コンストラクター内のバインド関数: コンパイル後、関数のプロトタイプに配置されるだけでなく、インスタンス化されるたびに生成されます。 . 現在のインスタンス コンテキストの変数をバインドします (this.b = this.b.bind(this))。

  • アロー関数: babel がコンパイルされた後、インスタンス化されるたびに、defineProperty が呼び出され、アロー関数のコンテンツが現在のインスタンス コンテキストにバインドされます。

  • コンパイル結果から判断すると、実際の開発ではコンテキストをバインドする必要がある場合はアロー関数を使用するのが最適です。なぜなら、bind メソッドを使用すると、プロトタイプ関数が生成されるだけでなく、インスタンス化ごとに追加の関数も生成されるからです。

  • 更新

Yu Tengjing のコメントを読んだ後、私はもっと本質的なことを学びました。

class = 記号を使用して宣言されたメソッドと変数の場合は、インスタンスの属性として使用されますが、= 記号なしで宣言された属性の場合は、プロトタイプ チェーンに配置されます。たとえば、

class A {
    a() {
        
    }
    b = 2;
    c = () => {
    }
}

このクラスの場合、インスタンス化されると、b と c がインスタンスの属性として使用され、a はプロトタイプ チェーンに配置されます。

では、なぜこのように実装されるのでしょうか?実際、これは tc39 仕様で言及されていることがわかります: フィールド宣言

等号宣言が直接書かれている場合、それは実際にはフィールド宣言の構文であり、そのようなものを直接宣言するのと同等です。インスタンス属性。

トピックに戻る

前の問題を解決したら、トピックに戻りましょう。実際のコンパイル条件でのクラスのアロー関数のコンパイル結果を理解すると、問題を理解しやすくなります。

Q: サブクラスが通常の関数を使用してsayNameを宣言すると、実行上の問題が発生するのはなぜですか?

A: サブクラスが通常の関数を使用してsayNameを宣言した場合、サブクラスによって宣言されたsayNameがコンストラクターのプロトタイプに配置されます。ただし、基本クラスのsayNameはアロー関数を使用するため、各インスタンスは直接sayName変数を持つことになります。 JavaScript 変数のアクセス規則に従って、まず変数自体が検索され、見つからない場合はプロトタイプ チェーン上で検索されます。したがって、sayName を検索する場合、基本クラスによって宣言された SayName 関数を直接検索し、プロトタイプ チェーン上では検索しないため、問題が発生します。

Q: サブクラスでは、sayName の宣言にアロー関数が使用されているのに、実行には問題がないのはなぜですか?

A: es6 クラスが初期化されると、最初に基本クラスのコンストラクターが実行され、次に独自のコンストラクターが実行されます。したがって、基底クラスが初期化された後は、サブクラスで宣言されたアロー関数sayNameが基底クラスのアロー関数をオーバーライドするため、実行には問題ありません。

要約

arrow 関数についてはよく知っていると思っていましたが、騙されました。確かに、学習に終わりはありません。しかし、クラス内のアロー関数についてもより深く理解しています。

しかし、コメント エリアの皆さんから指摘を受けて、実際にはアロー関数が問題の原因ではないことがわかりました。クラス内で = 記号を使用して宣言された変数は、フィールド宣言の構文に属します。この方法で宣言された変数の場合、プロトタイプ チェーンにマウントされるのではなく、インスタンスのプロパティに直接マウントされます。

推奨チュートリアル: 「JS チュートリアル

以上がアロー関数を理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事は掘金社区で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
next.jsを使用してマルチテナントSaaSアプリケーションを構築する(バックエンド統合)next.jsを使用してマルチテナントSaaSアプリケーションを構築する(バックエンド統合)Apr 11, 2025 am 08:23 AM

私はあなたの日常的な技術ツールを使用して機能的なマルチテナントSaaSアプリケーション(EDTECHアプリ)を作成しましたが、あなたは同じことをすることができます。 まず、マルチテナントSaaSアプリケーションとは何ですか? マルチテナントSaaSアプリケーションを使用すると、Singの複数の顧客にサービスを提供できます

next.jsを使用してマルチテナントSaaSアプリケーションを構築する方法(フロントエンド統合)next.jsを使用してマルチテナントSaaSアプリケーションを構築する方法(フロントエンド統合)Apr 11, 2025 am 08:22 AM

この記事では、許可によって保護されたバックエンドとのフロントエンド統合を示し、next.jsを使用して機能的なedtech SaaSアプリケーションを構築します。 FrontEndはユーザーのアクセス許可を取得してUIの可視性を制御し、APIリクエストがロールベースに付着することを保証します

JavaScript:Web言語の汎用性の調査JavaScript:Web言語の汎用性の調査Apr 11, 2025 am 12:01 AM

JavaScriptは、現代のWeb開発のコア言語であり、その多様性と柔軟性に広く使用されています。 1)フロントエンド開発:DOM操作と最新のフレームワーク(React、Vue.JS、Angularなど)を通じて、動的なWebページとシングルページアプリケーションを構築します。 2)サーバー側の開発:node.jsは、非ブロッキングI/Oモデルを使用して、高い並行性とリアルタイムアプリケーションを処理します。 3)モバイルおよびデスクトップアプリケーション開発:クロスプラットフォーム開発は、反応および電子を通じて実現され、開発効率を向上させます。

JavaScriptの進化:現在の傾向と将来の見通しJavaScriptの進化:現在の傾向と将来の見通しApr 10, 2025 am 09:33 AM

JavaScriptの最新トレンドには、TypeScriptの台頭、最新のフレームワークとライブラリの人気、WebAssemblyの適用が含まれます。将来の見通しは、より強力なタイプシステム、サーバー側のJavaScriptの開発、人工知能と機械学習の拡大、およびIoTおよびEDGEコンピューティングの可能性をカバーしています。

javascriptの分解:それが何をするのか、なぜそれが重要なのかjavascriptの分解:それが何をするのか、なぜそれが重要なのかApr 09, 2025 am 12:07 AM

JavaScriptは現代のWeb開発の基礎であり、その主な機能には、イベント駆動型のプログラミング、動的コンテンツ生成、非同期プログラミングが含まれます。 1)イベント駆動型プログラミングにより、Webページはユーザー操作に応じて動的に変更できます。 2)動的コンテンツ生成により、条件に応じてページコンテンツを調整できます。 3)非同期プログラミングにより、ユーザーインターフェイスがブロックされないようにします。 JavaScriptは、Webインタラクション、シングルページアプリケーション、サーバー側の開発で広く使用されており、ユーザーエクスペリエンスとクロスプラットフォーム開発の柔軟性を大幅に改善しています。

pythonまたはjavascriptの方がいいですか?pythonまたはjavascriptの方がいいですか?Apr 06, 2025 am 12:14 AM

Pythonはデータサイエンスや機械学習により適していますが、JavaScriptはフロントエンドとフルスタックの開発により適しています。 1. Pythonは、簡潔な構文とリッチライブラリエコシステムで知られており、データ分析とWeb開発に適しています。 2。JavaScriptは、フロントエンド開発の中核です。 node.jsはサーバー側のプログラミングをサポートしており、フルスタック開発に適しています。

JavaScriptをインストールするにはどうすればよいですか?JavaScriptをインストールするにはどうすればよいですか?Apr 05, 2025 am 12:16 AM

JavaScriptは、最新のブラウザにすでに組み込まれているため、インストールを必要としません。開始するには、テキストエディターとブラウザのみが必要です。 1)ブラウザ環境では、タグを介してHTMLファイルを埋め込んで実行します。 2)node.js環境では、node.jsをダウンロードしてインストールした後、コマンドラインを介してJavaScriptファイルを実行します。

クォーツでタスクが開始される前に通知を送信する方法は?クォーツでタスクが開始される前に通知を送信する方法は?Apr 04, 2025 pm 09:24 PM

Quartzタイマーを使用してタスクをスケジュールする場合、Quartzでタスク通知を事前に送信する方法、タスクの実行時間はCron式によって設定されます。今...

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター

SublimeText3 英語版

SublimeText3 英語版

推奨: Win バージョン、コードプロンプトをサポート!