持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情
前言
在 JS 中,创建类有两种方式,一种通过 function 定义;另一种是通过 class 定义。
而想要创建类的实例,还需要通过 new 创建;new 运算符的主要作用就是根据定义的类,生成相应的实例。
创建实例
创建实例主要是通过以下几个步骤:
- 创建一个空的对象
newObject,作为实例的上下文;- 将类上的原型放在
newObject的原型链上,使得newObject可以调用类中定义的函数;- 将
newObject作为this,执行类;- 判断类执行后是否有返回一个对象,如果有,则返回该对象;如果没有,则返回
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 !