初步了解 JS 继承

169 阅读2分钟

原型链

思想

利用原型让一个引用类型继承另一个引用类型的属性和方法。

方式

将子类的原型设置为父类的实例。

实现

function SuperType() {}
function SubType() {}

SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;

问题

  • 问题1。最主要的问题来自包含引用类型值的原型。包含引用类型值的原型属性会被所有实例共享。
function SuperType() {
    this.number = [1, 2, 3];
}
function SubType() {}

SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;

let ins1 = new SubType();
let ins2 = new SubType();
ins1.number[0] = 11;
console.log(ins2.number); // [11, 2, 3] 
  • 问题2。在创建子类型的实例时,不能向超类型的构造函数传递参数。实际上,应该说时没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数。

借用构造函数

思想

在子类型的构造函数内部调用超类型的构造函数。

实际上就是将超类型的代码在子类中执行一遍,使子类型拥有超类型的属性的副本。

实现

function SuperType() {
    this.num = [1, 2, 3];
}
function SubType() {
	// 继承 SuperType
	// 注意需要用 call 或 apply
    SuperType.call(this);
}

比较

  • 相对于原型链继承,借用构造函数不存在引用类型的原型属性被所有实例共享的问题,因为每个实例都有超类中属性的副本。

  • 可以向超类型构造函数传递参数

问题

  • 在超类型的原型中定义的方法,对子类型是不可见的。

组合继承

思想

结合原型链和借用构造函数两种方式。

使用原型链实现对原型属性和方法的继承,使用借用构造函数实现对实例属性的继承。

实现

function SuperType() {}
function SubType() {
    // 借用构造函数继承
    SuperType.call(this);
}

// 原型链继承
SubType.prototype = SuperType;
SubType.prototype.constructor = SubType;

参考

  • 《JavaScript 高级程序设计》(第3版)