Heim  >  Artikel  >  Web-Frontend  >  js-Vererbungsimplementierung

js-Vererbungsimplementierung

jacklove
jackloveOriginal
2018-06-15 16:28:221343Durchsuche

Mehrere Möglichkeiten zur Implementierung der Vererbung in JS

Vorwort

JS ist eine objektorientierte, schwach typisierte Sprache, Vererbung ist auch sehr leistungsfähig Eines der Merkmale. 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 zuerst 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. Prototypenkette Vererbung

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

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. Eine sehr reine Vererbungsbeziehung, die Instanz ist das untergeordnete Element. Eine Instanz einer Klasse ist auch eine Instanz der übergeordneten Klasse

  2. Die übergeordnete Klasse fügt neue Prototypmethoden/Prototypattribute hinzu, die sein können Zugriff durch Unterklassen

  3. Einfach, leicht zu implementieren

Nachteile:

  1. Wenn Sie möchten Wenn Sie einer Unterklasse Attribute und Methoden hinzufügen, müssen Sie einer Anweisung wie new Animal() Ausführung folgen, kann nicht im Konstruktor platziert werden

  2. Mehrfachvererbung kann nicht implementiert werden

  3. Referenzeigenschaften aus dem Prototypobjekt werden von allen Instanzen gemeinsam genutzt (bitte fragen Sie nach Einzelheiten. Siehe Anhangcode: Beispiel 1)

  4. Beim Erstellen einer Unterklasseninstanz können keine Parameter übergeben werden zum übergeordneten Klassenkonstruktor

Empfohlener Index: ★★ (Zwei schwerwiegende Fehler in 3 und 4)

2. Strukturelle Vererbung

Kern: Die Verwendung des Konstruktors der übergeordneten Klasse zum Erweitern der Unterklasseninstanz entspricht dem Kopieren der übergeordneten Klasse. Geben Sie Unterklassen Instanzattribute (es wird kein Prototyp verwendet)

function Cat(name){
  Animal.call(this);
  this.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

Funktionen:

  1. Lösen Sie das Problem in 1, dass Unterklasseninstanzen Referenzattribute der übergeordneten Klasse gemeinsam nutzen

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

  3. Sie können Mehrfachvererbung implementieren (mehrere übergeordnete Klassenobjekte aufrufen)

Nachteile:

  1. Instanzen sind keine Instanzen von Die übergeordnete Klasse, aber nur Instanzen der Unterklasse

  2. können nur vererbt werden. Die Instanzattribute und -methoden der übergeordneten Klasse können die Prototypattribute/-methoden nicht erben

  3. Funktionswiederverwendung kann nicht erreicht werden. Jede Unterklasse verfügt über eine Kopie der übergeordneten Klasseninstanzfunktion, was sich auf die Leistung auswirkt

Empfehlungsindex: ★★ (Nachteil 3)

3. Instanzvererbung

Kern: Fügen Sie neue Funktionen zu übergeordneten Klasseninstanzen hinzu, da die Unterklasseninstanz

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

Funktionen:

zurückgibt
  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('Tom');
var kissy = new Cat('Kissy');
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属性值已经变化了。

本文讲解了js的继承实现相关内容,更多相关内容请关注php中文网。
相关推荐:


Das obige ist der detaillierte Inhalt vonjs-Vererbungsimplementierung. 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