原型链

原型与继承 - 图1

JavaScript 原型链

基本上所有函数都含有 prototype 原型属性,除了 Function.prototype.bind() 方法生成的函数

  1. const foo = Function.prototype.bind()
  2. typeof foo // -> "function"
  3. foo.prototype === undefined // -> true

new 过程

  1. 新建空对象 {}
  1. var obj = {}
  1. 设置对象 constructor 属性为构造函数,根据引擎环境设置原型属性
  1. obj.__proto__ = Fn.prototype
  1. 使用新对象调用函数构造器,上下文 this 被指向该对象
  1. Fn.call(obj)
  1. 返回新对象(引用地址)。

注意:若构造函数最终返回值类型为基本数据类型(numberstringbooleannullundefined),则 new 之后返回刚刚创建的实例对象;若构造函数返回值类型为引用类型,则返回这个引用值

Function.proto === Function.prototype

如图:

原型与继承 - 图2

解析:

  • Object.prototype 由引擎创建,不是由 Object() 函数创建。所有实例都是对象,但是对象不一定都是实例。

  • Function.prototype 也由引擎创建。首先引擎创建了 Object.prototype ,然后创建了 Function.prototype ,并且通过 __proto__ 将两者联系了起来

  • 不是所有函数都是 new Function() 产生的。有了 Function.prototype 以后才有了 function Function() ,然后其他的构造函数都是 function Function() 生成的。

原型与继承 - 图3

实现继承

ES5 写法:

  1. function Super() {}
  2. Super.prototype.getNumber = function() {
  3. return 1
  4. }
  5. function Sub() {}
  6. Sub.prototype = Object.create(Super.prototype, {
  7. constructor: {
  8. value: Sub,
  9. enumerable: false,
  10. writable: true,
  11. configurable: true
  12. }
  13. })
  14. const s = new Sub()
  15. s.getNumber() // -> 1

ES6 写法:

  1. class SubDate extends Date {
  2. logTime () {
  3. console.log(`Time: ${this.getTime()}`)
  4. }
  5. }
  6. const myDate = new SubDate()
  7. myDate.getTime() // -> xxxxxxxxxxxxx
  8. myDate.logTime() // -> Time: xxxxxxxxxxxxx

[参考资料]