new 没有那么容易实现

说起 JavaScript 当中的 new 关键字,有一段很有趣的历史。其实 JavaScript 创造者 Brendan Eich 实现 new 是为了获得更高的流行度,它是强行学习 Java 的一个残留产出,他想让 JavaScript 成为 Java 的小弟。很多人认为这个设计掩盖了 JavaScript 中真正的原型继承,只是表面上看,更像是基于类的继承。

这样的误会使得很多传统 Java 开发者并不能很好理解 JavaScript。实际上,我们前端工程师应该明白,new 关键字到底做了什么事情。

  • step1:首先创建一个空对象,这个对象将会作为执行 new 构造函数() 之后,返回的对象实例
  • step2:将上面创建的空对象的原型(__proto__),指向构造函数的 prototype 属性
  • step3:将这个空对象赋值给构造函数内部的 this,并执行构造函数逻辑
  • step4:根据构造函数执行逻辑,返回第一步创建的对象或者构造函数的显式返回值

因为 new 是 JavaScript 的关键字,我们不能直接覆盖,实现一个 newFunc 来进行模拟,预计使用方式:

function Person(name) {
  this.name = name
}

const person = new newFunc(Person, 'lucas')

console.log(person)

// {name: "lucas"}

  

实现为:

function newFunc(...args) {
  // 取出 args 数组第一个参数,即目标构造函数
  const constructor = args.shift()

  // 创建一个空对象,且这个空对象继承构造函数的 prototype 属性
  // 即实现 obj.__proto__ === constructor.prototype
  const obj = Object.create(constructor.prototype)

  // 执行构造函数,得到构造函数返回结果
  // 注意这里我们使用 apply,将构造函数内的 this 指向为 obj
  const result = constructor.apply(obj, args)

  // 如果造函数执行后,返回结果是对象类型,就直接返回,否则返回 obj 对象
  return (typeof result === 'object' && result != null) ? result : obj
}

  

上述代码并不复杂,几个关键点:

  • 使用 Object.create 将 obj 的 __proto__ 指向为构造函数的原型
  • 使用 apply 方法,将构造函数内的 this 指向为 obj
  • 在 newFunc 返回时,使用三目运算符决定返回结果

我们知道,构造函数如果有显式返回值,且返回值为对象类型,那么构造函数返回结果不再是目标实例。如下代码:

function Person(name) {
  this.name = name
  return {1: 1}
}

const person = new Person(Person, 'lucas')

console.log(person)

// {1: 1}

  

了解这些注意点,对于理解 newFunc 的实现就不再困难。

猜你喜欢

转载自www.cnblogs.com/yipinxuan/p/11275198.html
new