JavaScript之重新谈谈继承

JavaScript中继承的方法

今天简单的总结下JavaScript中的继承,很多人的博客来自于红宝书、抑或是其他资料。把JavaScript的继承总结出了很多方法,比如:

  1. 原型法
  2. 类抄写法
  3. 组合法
  4. 组合寄生法

我一直觉得很莫名其妙,然后各种技术博客开始对 1~4的各种方法谈论他的利弊。

实际上呢,我认为 1~3这种就不算是完整的解决方案,不明白他们为什么要把简单的事情讲的那么复杂。

原型链

讲继承就先要讲JavaScript中继承使用的底层原理,就是原型链。原型链的设计可以用4句话概括:

  1. 构造函数,可以 new 一个对象的实例。构造函数相当于类。实例就是类生成的具体实例对象。
  2. 每一个构造函数拥有, .prototype属性(显式属性),即原型对象,用来保留方法或属性
  3. 每一个实例对象,拥有 __proto__属性(隐式属性),指向构造函数的原型对象。
  4. 当实例对象无法在自身寻找到方法,即去 __proto__上寻找,找不到就再去 对象的 __proto__上寻找,即原型链寻找

继承

当子类希望构建的实例,找不到属性方法,可以顺着原型链,从父类的原型上寻找方法,以此类推。如此就实现了继承。 一切方法都是围绕着这个来的。

Child 继承 Parent,如下面代码所示,即完成了符合要求的继承:

function Parent() {
    // ....
}

function Child (...args) {
    Parent.call(this, ...args)
    // ....
}

Child.prototype = Object.new(Parent.prototype);
Child.prototype.constructor = Child;

解释:

  1. 获得父类的属性

Child的构造函数中,运营了Parent的构造函数,改变了this,传参初始化。 这样Child得到了Parent的属性。

  1. 设置原型和构造器

Object.create(A)的作用是,创建以A作为 原型的一个对象实例。

Child.prototype = Object.new(Parent.prototype); 的作用是创建了以 Parent.prototype为原型的一个实例对象,并且作为 Child的原型。这样相当于 建立了 Child.prototype 对象--- Parent.prototype的关系。

按照原型的要求,正确的给原型对象设置构造器属性,以让原型对象可以找到构造函数。 Child.prototype.constructor = Child;

这样就完成了。

const child1 = new Child() 时,child1 实例的 __proto__指向 Child.prototype。 当child1找不到方法,就会查找 Child.prototype, 而 Child.prototype 也找不到就会找他的 __proto__也就是 Parent.prototype

这样就符合要求的串联起来。

至于其他的各种方法,首先残缺的方法,根本不够完整,不应该作为方法记忆。

其次,更高级的变种方法,就是将这种基本方法进行工厂式或者其他形式封装,本质上不变。

参考

Mark24

Everything can Mix.