JavaScript继承方式

2017年09月28日Web前端

作为可以面向对象的语言,JS也有实现继承的方式。 首先,既然说到了继承,我们先实现个父类。

var Far = function (name) {
    this.name = name;
}
Far.prototype.showName = function () {
    console.log(this.name);
}

一、原型链继承

原型链继承的方式十分简单,

var Son = function () {

}
// 此处是prototype的覆盖
Son.prototype = new Far('hello');

var ss = new Son();
console.log(ss.showName());  // 'hello'

原型继承方式的缺点:

  • 子类增加的原型方法必须在new 之后,否则会被prototype覆盖。
  • 不支持多继承。
  • 父类的引用类型的变量是共享的。
  • 创建子类时,无法向父类传递参数。

二、构造继承

没有使用到原型,实际上是将父类的属性复制给子类。

var Son = function (name) {
    Far.call(this);
    this.name = name;
}

var ss = new Son('ko');
console.log(ss.name); // 'ko'
ss.showName();        // Uncaught TypeError: ss.showName is not a function

可以明显的看到我们无法调用到父类原型的方法。 缺点:

  • 只能继承父类的属性和方法,不能继承父类原型的方法。
  • 无法实现函数的复用。

三、实例继承

其实就是将父类的实例增加属性后,返回出该对象。

var Son = function (name) {
   var instance = new Far();
   instance.name = name;

   return instance;
}

var ss = new Son('ko');
ss.showName();         // 'ko'

缺点:

  • 不支持多继承。
  • 实例实际上是父类的实例。

四、拷贝继承

var Son = function (name) {
    var instance = new Far();

    for (var i in instance) {
        Son.prototype\[i\] = instance\[i\];
    }
    Son.prototype.name = name;
}

var ss = new Son('ko');
ss.showName();            // 'ko'

缺点:

  • 比较浪费性能。
  • 无法获取父实例下的不可枚举的类型。

五、组合继承

通过调用父类的构造函数,继承父类的的属性,并以父类的实例作为子类的原型。

var Son = function (name) {
    Far.call(this);

    this.name = name;
}
Son.prototype = new Far();
Son.prototype.constructor = Son;

var ss = new Son('ko');
ss.showName();  // 'ko'

该方法弥补了构造继承的缺陷,使得他既可以继承实例的属性和方法,也可以继承原型的属性和方法。 缺点:

  • 调用了两次父类的构造函数(实例将原型上的屏蔽了)。

六、寄生组合继承

通过寄生解决组合继承中实例两次的问题。

function inheritPrototype (subObj, superObj) {
    var proObj = Object.create(superObj.prototype); // 复制父类superObj的原型对象
    proObj.constructor = subObj;                    // constructor指向子类构造函数
    subObj.prototype = proObj;                      // 再把这个对象给子类的原型对象
}

var Son = function (name) {
    Far.call(this);

    this.name = name;
}

inheritPrototype(Son, Far);
var ss = new Son('ko');

ss.showName();    // 'ko'

其中Object.create()方法需要在IE9+的环境下,兼容的话,可以通过以下这种方式去兼容。

function object(o){
    function F () {};
    F.prototype = o;
    return new F();
}