js 6种继承方式及优缺点

1、原型链继承
原理:把子类的 prototype(原型对象)直接设置为父类的实例

缺点:因为子类只进行一次原型更改,所以子类的所有实例保存的是同一个父类的值。
当子类对象上进行值修改时,如果是修改的原始类型的值,那么会在实例上新建这样一个值;
但如果是引用类型的话,他就会去修改子类上唯一一个父类实例里面的这个引用类型,这会影响所有子类实例

function Parent() {
  this.name = "parent";
  this.arr = [1, 2, 3];
}

function Child() {
  this.type = "child";
}

Child.prototype = new Parent();
var c1 = new Child();
var c2 = new Child();
c1.__proto__ === c2.__proto__;

2、构造函数继承
在构造函数中 使用Parent.call(this)的方法继承父类属性。

原理: 将子类的 this 使用父类的构造函数跑一遍

缺点: Parent 原型链上的属性和方法并不会被子类继承

function Parent(name, id){
  this.id = id;
  this.name = name;
  this.printName = function(){
    console.log(this.name);
  }
}
Parent.prototype.sayName = function(){
  console.log(this.name);
};
function Child(name, id){
  Parent.call(this, name, id);
  // Parent.apply(this, arguments);
}
var child = new Child("jin", "1");
child.printName(); // jin
child.sayName() // Error

3、组合继承
组合构造函数中使用 call 继承和原型链继承。

原理:子类构造函数中使用Parent.call(this);的方式可以继承写在父类构造函数中 this 上绑定的各属性和方法;
使用Child.prototype = new Parent()的方式可以继承挂在在父类原型上的各属性和方法

缺点: 父类构造函数在子类构造函数中执行了一次,在子类绑定原型时又执行了一次

function Parent(name, id){
  this.id = id;
  this.name = name;
  this.list = ['a'];
  this.printName = function(){
    console.log(this.name);
  }
}
Parent.prototype.sayName = function(){
  console.log(this.name);
};
function Child(name, id){
  Parent.call(this, name, id);
  // Parent.apply(this, arguments);
}
Child.prototype = new Parent();
var child = new Child("jin", "1");
child.printName(); // jin
child.sayName() // jin

var a = new Child();
var b = new Child();
a.list.push('b');
console.log(b.list); // ['a']

4、原型式继承
原理:类似Object.create,用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象,结果是将子对象的__proto__指向父对象

缺点:共享引用类型

var parent = {
  names: ['a']
}
function copy(object) {
  function F() {}
  F.prototype = object;    
  return new F();
}
var child = copy(parent);

5、寄生式继承
原理:二次封装原型式继承,并拓展
优点:可添加新的属性和方法

function createObject(obj) {
  var o = copy(obj);
  o.getNames = function() {
    console.log(this.names);
    return this.names;
  }
  return o;
}

6、寄生组合继承
原理:改进组合继承,利用寄生式继承的思想继承原型

function inheritPrototype(subClass, superClass) {
  // 复制一份父类的原型
  var p = copy(superClass.prototype);
  // 修正构造函数
  p.constructor = subClass;
  // 设置子类原型
  subClass.prototype = p;
}

function Parent(name, id){
  this.id = id;
  this.name = name;
  this.list = ['a'];
  this.printName = function(){
    console.log(this.name);
  }
}
Parent.prototype.sayName = function(){
  console.log(this.name);
};
function Child(name, id){
  Parent.call(this, name, id);
  // Parent.apply(this, arguments);
}
inheritPrototype(Child, Parent);
上一篇:Lua : 类工厂实现继承关系


下一篇:Nodejs中的流Stream是什么?