一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情。
前言
new关键字在很多编程语言中都有,js中也不例外,今天就来看看new操作到底是如何实现的,让我们来自己实现一个new操作,在模拟实现之前我们要首先知道new到底干了什么,它有什么特性。
new的特点
我们先来看个例子,如下
function animal(color,species){
this.color = color
this.species = species
}
animal.prototype.attribute = 'run'
animal.prototype.sayColor = function(){
console.log('I am' + this.color)
}
let dog = new animal('white','dog')
console.log(dog.color)
console.log(dog.species)
console.log(dog.attribute)
dog.sayColor()
运行截图如下:
由此可以看出:
- new 的实例dog可以访问到构造函数的属性
- 可以访问到构造函数原型上的属性或方法
我们没办法直接写一个new这种类型的东西,所以只能用一个函数来代替,就叫做myNew()吧,这里myNew的第一个参数就是构造函数,后边的参数是传入构造函数的参数,大致的步骤是:
- 首先我们要生成一个对象,因为new得到的结果是一个对象
- 这个对象要可以访问构造函数的属性,这点可以通过实例的__proto__来实现(实例.proto=Constructor.proto)
- 我们还要改变this的指向,因为new的对象中,this是指向实例的
function myNew(){
let obj = new Object()
Constructor = [].shift.call(arguments)
obj.__proto__ = Constructor.prototype
Constructor.apply(obj,arguments)
return obj
}
我们在来用上面的例子来试一试
let dog = myNew(animal,'white','dog')
console.log(dog.color)
console.log(dog.species)
console.log(dog.attribute)
dog.sayColor()
结果如下
非常nice,成功了
上面的代码实现了new的基本功能,但new还有一个特性,那就是如果构造函函数有return结果,那实例能访问到的东西就会发生变化了,如题如下
- 如果构造函数返回的是对象,那实例只能访问构造函数中return的对象中的属性或方法
- 如果返回的是基本数据类型,那就不用管,和没返回是一样的 基于上面的两点,再来改善一下我们的myNew
function myNew(){
let obj = new Object()
Constructor = [].shift.call(arguments)//拿到构造函数
obj.__proto__ = Constructor.prototype
result = Constructor.apply(obj,arguments)
return typeof result==='object'? result||obj: obj //防止构造函数返回null的情况
}
总结
new的模拟实现大概就是这样,其中的重点就是要知道new到底都干了什么事,然后一件件来实现这些事就可以了