extendsReact.Component
ES6classES5
构造函数、原型对象和实例之间的关系

要弄懂extends继承之前,先来复习一下构造函数、原型对象和实例之间的关系。

代码表示:

笔者画了一张图表示:

构造函数

ES6 extends 继承做了什么操作
ES6

其中这段代码里有两条原型链,不信看具体代码。

一图胜千言,笔者也画了一张图表示,如图所示:

构造函数(Parent)

结合代码和图可以知道, ES6extends 继承,主要就是:

  1. 把子类构造函数( Child)的原型( proto)指向了父类构造函数( Parent)。
  2. 把子类实例 child的原型对象( Child.prototype) 的原型( proto)指向了父类 parent的原型对象( Parent.prototype)。这两点也就是图中用不同颜色标记的两条线。
  3. 子类构造函数 Child继承了父类构造函数 Preant的里的属性。使用 super调用的( ES5则用 call或者 apply调用传参)。也就是图中用不同颜色标记的两条线。

看过《JavaScript高级程序设计-第3版》 章节 6.3继承的读者应该知道,这2和3小点,正是寄生组合式继承,书中例子没有第1小点。

1和2小点都是相对于设置了 proto链接。那问题来了,什么可以设置 proto链接呢。

设置 proto
newObject.createObject.setPrototypeOf__proto__
__proto__
__proto__new
new 做了什么
  1. 创建了一个全新的对象。
  2. 这个对象会被执行 [[Prototype]](也就是 proto)链接。
  3. 生成的新对象会绑定到函数调用的 this。
  4. 通过 new创建的每个对象将最终被 [[Prototype]]链接到这个函数的 prototype对象上。
  5. 如果函数没有返回对象类型 Object(包含 Functoin, Array, Date, RegExg, Error),那么 new表达式中的函数调用会自动返回这个新的对象。
Object.create:ES5提供的
Object.create(proto,[propertiesObject])__proto__
undefinedMDN Object.create()
Object.setPrototypeOf:ES6提供的
Object.setPrototypeOf()Object.setPrototypeOf(obj,prototype)
nodejs
extends的ES5版本实现
ES6 extends__proto__

我们完全可以把上述 ES6的例子通过 babeljs转码成 ES5来查看,更严谨的实现。

如果对JS继承相关还是不太明白的读者,推荐阅读以下书籍的相关章节,可以自行找到相应的 pdf版本。

推荐阅读JS继承相关的书籍章节

《JavaScript高级程序设计第3版》第6章——面向对象的程序设计

6种继承的方案,分别是原型链继承、借用构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合式继承。图灵社区本书地址,后文放出 github链接,里面包含这几种继承的代码 demo。

《JavaScript面向对象编程第2版》第6章——继承

12种继承的方案:

  • 原型链法(仿传统)
  • 仅从原型继承法
  • 临时构造器法
  • 原型属性拷贝法
  • 全属性拷贝法(即浅拷贝法)
  • 深拷贝法
  • 原型继承法
  • 扩展与增强模式
  • 多重继承法
  • 寄生继承法
  • 构造器借用法
  • 构造器借用与属性拷贝法

《ES6标准入门》第21章——class的继承

《深入理解ES6》第9章——JavaScript中的类

《你不知道的JavaScript》上卷第6章——行为委托和附录A(ES6中的class)

总结

继承对于JS来说就是父类拥有的方法和属性、静态方法等,子类也要拥有。子类中可以利用原型链查找,也可以在子类调用父类,或者从父类拷贝一份到子类等方案。

继承方法可以有很多,重点在于必须理解并熟。

悉这些对象、原型以及构造器的工作方式,剩下的就简单了。寄生组合式继承是开发者使用比较多的。

回顾寄生组合式继承,主要就是三点:

  • 子类构造函数的 proto指向父类构造器,继承父类的静态方法
  • 子类构造函数的 prototype的 proto指向父类构造器的 prototype,继承父类的方法。
  • 子类构造器里调用父类构造器,继承父类的属性。