この記事では、JS の継承 (プロトタイプ チェーン、コンストラクター、組み合わせ、プロトタイプ、寄生、寄生の組み合わせ、クラスの拡張) について詳しく説明します。これには特定の参照値があり、必要なときに一度参照できます。
正直に言うと、以前は「寄生組み合わせ継承」が最適であることを知るだけでよく、それを使用するには祖先のコードテンプレートが必要でした。最近、数週間にわたっていくつかのことを整理したいと考えています。この記事は、『JavaScript Advanced Programming』の内容を骨子として、ES6 クラスの関連内容を補足し、より理解しやすい観点から継承について説明します。
まずは全体的な感想を述べてみましょう。図に示すように、JS における継承は、後述するオブジェクト関数を使用するかどうかに応じて 2 つの部分に分けられます (Object.create は、この関数を標準化するための ES5 の新しいメソッドです)。
このうち、プロトタイプチェーン継承とプロトタイプ継承は同じ長所と短所を持ち、コンストラクター継承と寄生継承も対応しています。寄生組み合わせ継承は Object.create に基づいており、同時に組み合わせ継承を最適化し、完全な継承方法になります。 ES6 クラス拡張の結果は基本的に寄生組み合わせ継承と同じですが、実装が若干異なります。
早速本題に入りましょう。
上の図の上半分のプロトタイプチェーンの継承、コンストラクターの継承、および結合の継承については、インターネット上に多くのコンテンツがありますが、この記事では詳しく説明しません。要点のみを指摘します。一番分かりやすいと思うのは「JSにおける継承(前編)」の記事です。前半の内容をよく知らない場合は、最初にこの記事を読んでから、戻って読み続けてください。すでに内容を理解している場合は、この部分をすぐに飛ばしてください。さらに、このセクションの前半は、yq フロントエンドに関する継承記事 [1] から大幅に借用しています。
コア: 親クラスのインスタンスをサブクラスのプロトタイプとして使用する
SubType.prototype = new SuperType() // 所有涉及到原型链继承的继承方式都要修改子类构造函数的指向,否则子类实例的构造函数会指向SuperType。 SubType.prototype.constructor = SubType;
長所: 親クラスのメソッドを再利用できる
短所:
親クラスの参照属性が共有されるすべてのサブクラスのインスタンスによって
インスタンスを構築するときに、サブクラスは親クラスにパラメータを渡すことはできません
コア: 親クラスのコンストラクターの内容がサブクラスのコンストラクターにコピーされます。これは、すべての継承の中でプロトタイプを含まない唯一の継承です。
SuperType.call(SubType);
利点: プロトタイプ チェーンの継承とは完全に逆です。
親クラスの参照属性は共有されません
サブクラスはインスタンスを構築するときに親クラスにパラメータを渡すことができます
欠点: 親クラスのメソッドは再利用できず、サブクラスインスタンスのメソッドは個別に作成されるたびに変更されます。
コア: プロトタイプ継承とコンストラクター継承の組み合わせは、両方の利点を組み合わせたものです。
function SuperType() { this.name = 'parent'; this.arr = [1, 2, 3]; } SuperType.prototype.say = function() { console.log('this is parent') } function SubType() { SuperType.call(this) // 第二次调用SuperType } SubType.prototype = new SuperType() // 第一次调用SuperType
利点:
親クラスのメソッドを再利用できる
親クラスの参照プロパティが共有されない
インスタンスの構築時にサブクラスが親クラスにパラメータを渡すことができる
欠点:
親クラスのコンストラクターは 2 回呼び出され、1 回目は親クラスの name 属性と arr 属性をサブクラスのプロトタイプに追加します。親クラスをサブクラスのコンストラクターに追加することで、サブクラスのプロトタイプ内の同じ名前のパラメーターをオーバーライドします。この上書き状況はパフォーマンスの無駄を引き起こします。
コア: プロトタイプ継承のオブジェクト メソッドは、本質的にはパラメーター オブジェクトの浅いコピーです。
利点: 親クラスのメソッドを再利用できます
欠点:
親クラスの参照属性はすべてのサブクラスインスタンスで共有されます
インスタンスの構築時にサブクラスは親クラスにパラメータを渡すことができません
function object(o){ function F(){} F.prototype = o; return new F(); } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
ECMAScript 5 プロトタイプの継承は、新しい Object.create() メソッドで標準化されました。このメソッドは 2 つのパラメータを受け入れます。新しいオブジェクトのプロトタイプとして使用されるオブジェクトと、(オプションで) 新しいオブジェクトの追加プロパティを定義するオブジェクトです。 Object.create() メソッドは、1 つのパラメーターが渡された場合、object() メソッドと同じように動作します。 ——「JAVASCript 高度なプログラミング」
したがって、上記のコードは次のように変換できます
var yetAnotherPerson = object(person); => var yetAnotherPerson = Object.create(person);
コア: プロトタイプ継承を使用してターゲット オブジェクトの浅いコピーを取得し、この浅いコピーの機能を強化します。
長所と短所: アイデアが 1 つだけあり、利点はありません
function createAnother(original){ var clone=object(original); //通过调用函数创建一个新对象 clone.sayHi = function(){ //以某种方式来增强这个对象 alert("hi"); }; return clone; //返回这个对象 } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi"
組み合わせ継承には、親クラスのコンストラクターを 2 回呼び出すという欠点があることを述べましたが、寄生組み合わせ継承はこの問題を解決できます。 。
function inheritPrototype(subType, superType){ var prototype = object(superType.prototype); // 创建了父类原型的浅复制 prototype.constructor = subType; // 修正原型的构造函数 subType.prototype = prototype; // 将子类的原型替换为这个原型 } function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); this.age = age; } // 核心:因为是对父类原型的复制,所以不包含父类的构造函数,也就不会调用两次父类的构造函数造成浪费 inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function(){ alert(this.age); }
長所と短所: これは継承の完璧な方法です。
コア: ES6 継承の結果は、寄生組み合わせ継承と似ています。本質的に、ES6 継承は一種の構文糖衣です。ただし、寄生結合継承は最初にサブクラス インスタンスの this オブジェクトを作成し、それを拡張します。一方、ES6 は最初に親クラス インスタンス オブジェクトのプロパティとメソッドを this に追加し (そのため、最初にスーパー メソッドを呼び出す必要があります)、次にサブクラス インスタンス オブジェクトをクラスのコンストラクターで変更します。
class A {} class B extends A { constructor() { super(); } }
ES6 における継承の具体的な原則:
class A { } class B { } Object.setPrototypeOf = function (obj, proto) { obj.__proto__ = proto; return obj; } // B 的实例继承 A 的实例 Object.setPrototypeOf(B.prototype, A.prototype); // B 继承 A 的静态属性 Object.setPrototypeOf(B, A);
ES6继承与ES5继承的异同:
相同点:本质上ES6继承是ES5继承的语法糖
不同点:
ES6继承中子类的构造函数的原型链指向父类的构造函数,ES5中使用的是构造函数复制,没有原型链指向。
ES6子类实例的构建,基于父类实例,ES5中不是。
ES6 Class extends是ES5继承的语法糖
JS的继承除了构造函数继承之外都基于原型链构建的
可以用寄生组合继承实现ES6 Class extends,但是还是会有细微的差别
相关推荐:
AngularJs自定义指令可以如何来设置以及自定义指令的命名规范
以上がJS 継承の詳細な紹介 (プロトタイプ チェーン、コンストラクター、組み合わせ、プロトタイプ、寄生、寄生の組み合わせ、クラス拡張)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。