私は以前、アロー関数についてはすでによく理解していると感じていましたが、再びだまされることはありえないと感じていました。しかし、数日前に非常に奇妙な問題に遭遇し、長い間悩んだ結果、それはアロー機能による落とし穴であることがわかりました。したがって、次の記事があります~
問題の説明
たとえば、基本クラス 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') } }
"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('c'); }); this.b = this.b.bind(this); } _createClass(A, [{ key: "a", value: function a() { console.log('a'); } }, { key: "b", value: function b() { console.log('b'); } }]); return A; }();
var A = /*#__PURE__*/function () { function A() { _classCallCheck(this, A); _defineProperty(this, "c", function () { console.log('c'); }); this.b = this.b.bind(this); } _createClass(A, [{ key: "a", value: function a() { console.log('a'); } }, { key: "b", value: function b() { console.log('b'); } }]); return A; }();
class = 記号を使用して宣言されたメソッドと変数の場合は、インスタンスの属性として使用されますが、= 記号なしで宣言された属性の場合は、プロトタイプ チェーンに配置されます。たとえば、
class A { a() { } b = 2; c = () => { } }
arrow 関数についてはよく知っていると思っていましたが、騙されました。確かに、学習に終わりはありません。しかし、クラス内のアロー関数についてもより深く理解しています。
しかし、コメント エリアの皆さんから指摘を受けて、実際にはアロー関数が問題の原因ではないことがわかりました。クラス内で = 記号を使用して宣言された変数は、フィールド宣言の構文に属します。この方法で宣言された変数の場合、プロトタイプ チェーンにマウントされるのではなく、インスタンスのプロパティに直接マウントされます。
推奨チュートリアル: 「JS チュートリアル 」
以上がアロー関数を理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。