JS-手写 new

126 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情

前言

JS 中,创建有两种方式,一种通过 function 定义;另一种是通过 class 定义。

而想要创建的实例,还需要通过 new 创建;new 运算符的主要作用就是根据定义的,生成相应的实例。

创建实例

创建实例主要是通过以下几个步骤:

  1. 创建一个空的对象 newObject,作为实例的上下文;
  2. 上的原型放在 newObject 的原型链上,使得 newObject 可以调用中定义的函数;
  3. newObject 作为 this,执行
  4. 判断执行后是否有返回一个对象,如果有,则返回该对象;如果没有,则返回 newObject;

举个例子

定义如下的:

function Person (name = 'default', age = 18) {
  this.name = name
  this.age = age
}

Person.prototype.say = function () {
  console.log(`I'm ${this.name}, my age is ${this.age} !`)
}

使用 new 创建类的实例,如下:

const person = new Person('Bear', 18)
console.log('person:', person)
// person: {name: 'Bear', age: 18}
person.say()
// I'm Bear, my age is 18 !

了解了 new 的基本实现和使用,接下来就开始手写实现。

手写实现

首先定义手写的 new,参数分为两个部分,一部分是,另一部分是执行的参数;而返回值是一个对象,所以定义如下:

/**
 * 手写 new
 * @param { function } builder 类或者构造函数
 * @param { any[] } arg 参数
 * @returns { object }
 */
function myNew (builder, ...arg) {
  const newObject = {}
  return newObject
}

然后就是把prototype 作为 newObject 的原型:

function myNew (builder, ...arg) {
  const newObject = {}
  // 原型处理
  newObject.__proto__ = builder.prototype
  return newObject
}

最后就是改变执行时的 this,然后执行,并且保存返回结果;return 时,判断执行后返回值 returnValue 的是否为一个对象,如果是,则返回 returnValue,不是则返回 newObject:

function myNew (builder, ...arg) {
  const newObject = {}
  newObject.__proto__ = builder.prototype
  // 通过 call、apply、bind 改变 类 的 this,然后执行
  const returnValue = builder.call(newObject, ...arg)
  // 返回值处理,排除 returnValue 是 null 的情况
  return returnValue && typeof result === 'Object' ? result : newObject
}

至此,基本实现完成,测试一把:

const myPerson = myNew(Person, 'Bear White', 20)
console.log('my person:', myPerson)
// my person: {name: 'Bear White', age: 20}
myPerson.say()
// I'm Bear White, my age is 20 !