JS | 手写一个new

130 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 23 天,点击查看活动详情

new关键字的作用就是创建一个构造函数的实例对象

每一次在写代码的时候,可能会使用到 new Array,new Function,new ...等等,被频繁使用到的 new 指令,具体做了那些事?

JS 的 new 操作符做了哪些事情

new 操作符新建了一个空对象,这个对象原型指向构造函数的 prototype,执行构造函数后返回这个对象。

运行如下代码,我们来观查一下运行结果:

function Student(name,score) {
	this.name = name
	this.score = score
	console.log('Student')
}
let s = new Student("张三",100)
console.log(s)

运行结果:

image.png

展开 prototype :

image.png

注:如果不使用 new 来声明,不会生成对象,而是调用普通的函数

手写一个new

  • 创建一个新的空对象 { }
  • 使新对象的 __proto__ 指向原函数的prototype(绑定 fn 的原型)
  • 改变this指向(指向前面创建的新的空对象 )并执行该函数,保存执行结果
  • 使用 instanceof 来判断判断上一步的结果是否是 null 或 undefined
    • 如果是,返回之前的新对象
    • 如果不是则返回执行结果 result

实现代码如下:

function myNew(fn, ...args) {
  let obj = {}
  obj.__proto__ = fn.prototype
  let result = fn.apply(obj, args)
  return result instanceof Object ? result : obj
}

第二步也可以这样来写:省略掉函数的参数:

image.png

运行结果

我们来使用上面的代码来进行验证:

function Student(name,score) {
	this.name = name
	this.score = score
	console.log('Student')
}
let s = myNew(Student,"张三",100)
console.log(s)

运行结果可以看到与原来直接使用 new 时一致:

image.png

关于 arguments

删除并获取参数的第一项:

[].shift.call( arguments )
// 等效于
Array.prototype.shift.call( arguments )

由于 arguments 无法通过 shift() 来获取,所以需要借助数组的原型(原型上有 shift() 方法)。

这里没有使用arguments[0] 来获取第一个参数,是因为这样做不会改变 arguments,而调用 shift 会将 argument 的第一项删除。