Heim  >  Artikel  >  Web-Frontend  >  Mehrere Möglichkeiten zur Implementierung der Vererbung in JS

Mehrere Möglichkeiten zur Implementierung der Vererbung in JS

一个新手
一个新手Original
2017-09-23 09:30:101606Durchsuche

Vorwort

JS ist eine objektorientierte, schwach typisierte Sprache, und Vererbung ist ebenfalls eine ihrer sehr leistungsstarken Funktionen. Wie implementiert man also die Vererbung in JS? Warten wir ab.

So implementieren Sie die JS-Vererbung

Da wir die Vererbung implementieren möchten, müssen wir zunächst eine übergeordnete Klasse haben. Der Code lautet wie folgt:

// 定义一个动物类
function Animal (name) {
  // 属性
  this.name = name || 'Animal';
  // 实例方法
  this.sleep = function(){
    console.log(this.name + '正在睡觉!');
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};

1. Prototyp Kettenvererbung

Kern: Verwenden Sie die Instanz der übergeordneten Klasse als Prototyp der Unterklasse

function Cat(){ 
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true 
console.log(cat instanceof Cat); //true

Eigenschaften:

  1. Sehr reine Vererbungsbeziehung, die Instanz ist eine Instanz der Unterklasse und auch eine Instanz der übergeordneten Klasse

  2. Die übergeordnete Klasse verfügt über hinzugefügte Prototypmethoden/Prototypattribute, auf die zugegriffen werden kann nach Unterklassen

  3. Einfach und leicht zu implementieren

Nachteile:

  1. Wenn Sie hinzufügen möchten Attribute und Methoden zu einer Unterklasse hinzufügen, müssen Sie sie hinzufügen new Animal() Eine solche Anweisung wird später ausgeführt und kann nicht im Konstruktor platziert werden

  2. Mehrfachvererbung kann nicht implementiert werden

  3. Referenzeigenschaften aus dem Prototypobjekt werden von allen Instanzen gemeinsam genutzt (Einzelheiten finden Sie im Anhangcode: Beispiel 1)

  4. Beim Erstellen einer Unterklasseninstanz können Parameter nicht verwendet werden an den Konstruktor der übergeordneten Klasse übergeben werden

Empfohlener Index: ★★ (zwei schwerwiegende Fehler von 3 und 4)

2. Konstruktive Vererbung

Kern: Verwenden Sie den Konstruktor der übergeordneten Klasse, um die Instanz der Unterklasse zu erweitern, die gleich ist. Es dient dazu, die Instanzattribute der übergeordneten Klasse in die Unterklasse zu kopieren (es wird kein Prototyp verwendet)

<p style="margin-top: 15px;">function Cat(name){<br>  Animal.call(this);<br>  this.name = name || 'Tom';<br>}<br><br>// Test Code<br>var cat = new Cat();<br>console.log(cat.name);<br>console.log(cat.sleep());<br>console.log(cat instanceof Animal); // false<br>console.log(cat instanceof Cat); // true<br></p>

Funktionen:

  1. Lösen Sie 1, Unterklasseninstanzen teilen sich die übergeordnete Klasse. Probleme mit Referenzattributen

  2. Beim Erstellen einer Unterklasseninstanz können Sie Parameter an die übergeordnete Klasse übergeben

  3. Mehrfachvererbung kann erreicht werden (rufen Sie mehrere übergeordnete Klassen auf)

Nachteile:

  1. Instanz ist keine Instanz der übergeordneten Klasse, sondern eine Instanz der Unterklasse

  2. Nur ​​die Instanzattribute und -methoden der übergeordneten Klasse können vererbt und als Prototyp verwendet werden Attribute/Methoden können nicht vererbt werden

  3. Funktionswiederverwendung kann nicht erreicht werden. Jede Unterklasse hat eine Kopie der Instanzfunktion der übergeordneten Klasse

Empfehlungsindex: ★★ (Nachteil 3)

3、实例继承

核心:为父类实例添加新特性,作为子类实例返回

function Cat(name){
  var instance = new Animal();
  instance.name = name || 'Tom';
  return instance;
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false

特点:

  1. 不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果

缺点:

  1. 实例是父类的实例,不是子类的实例

  2. 不支持多继承

推荐指数:★★

4、拷贝继承

function Cat(name){
  var animal = new Animal();
  for(var p in animal){
    Cat.prototype[p] = animal[p];
  }
  Cat.prototype.name = name || 'Tom';
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

特点:

  1. 支持多继承

缺点:

  1. 效率较低,内存占用高(因为要拷贝父类的属性)

  2. 无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)

推荐指数:★(缺点1)

5、组合继承

核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
Cat.prototype = new Animal();

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true

特点:

  1. 弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法

  2. 既是子类的实例,也是父类的实例

  3. 不存在引用属性共享问题

  4. 可传参

  5. 函数可复用

缺点:

  1. 调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

推荐指数:★★★★(仅仅多消耗了一点内存)

6、寄生组合继承

核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
(function(){
  // 创建一个没有实例方法的类
  var Super = function(){};
  Super.prototype = Animal.prototype;
  //将实例作为子类的原型
  Cat.prototype = new Super();
})();

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true

特点:

  1. 堪称完美

缺点:

  1. 实现较为复杂

推荐指数:★★★★(实现复杂,扣掉一颗星)

附录代码:

示例一:

function Animal (name) {
  // 属性
  this.name = name || 'Animal';
  // 实例方法
  this.sleep = function(){
    console.log(this.name + '正在睡觉!');
  }
  //实例引用属性
  this.features = [];
}
function Cat(name){
}
Cat.prototype = new Animal();

var tom = new Cat();
var kissy = new Cat();

console.log(tom.name); // "Animal"
console.log(kissy.name); // "Animal"
console.log(tom.features); // []
console.log(kissy.features); // []

tom.name = 'Tom-New Name';
tom.features.push('eat');

//针对父类实例值类型成员的更改,不影响
console.log(tom.name); // "Tom-New Name"
console.log(kissy.name); // "Animal"
//针对父类实例引用类型成员的更改,会通过影响其他子类实例
console.log(tom.features); // ['eat']
console.log(kissy.features); // ['eat']

原因分析:

关键点:属性查找过程

执行tom.features.push,首先找tom对象的实例属性(找不到),
那么去原型对象中找,也就是Animal的实例。发现有,那么就直接在这个对象的
features属性中插入值。
在console.log(kissy.features); 的时候。同上,kissy实例上没有,那么去原型上找。
刚好原型上有,就直接返回,但是注意,这个原型对象中features属性值已经变化了。

Das obige ist der detaillierte Inhalt vonMehrere Möglichkeiten zur Implementierung der Vererbung in JS. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn