手动实现 new 关键字
new 做了哪些事
在实现 new 关键字之前我们需要了解 new 到底做了什么工作?
我们从一段简单的代码入手来看
javascript1function fn(name){ 2 this.name=name 3} 4fn.prototype.say=function (){ 5 alert(this.name) 6} 7const boy=new fn('qiuyanxi')
这段代码非常简单,它定义了一个构造函数,然后给了这个构造函数的原型一个名叫 say 的函数。
毫无疑问,当我调用 boy.say的时候会打印qiuyanxi,那么我们推断 new 做了什么?
- 首先一定会返回一个对象。
- 该对象内肯定有个 name 属性,值为
qiuyanxi。 - 既然这个对象可以调用 say 方法,说明也继承了 say 方法。
为了证明我们的猜想,我们从打印台查看一下boy 这个对象

推断正确,有一点值得我们注意,say 方法是在 boy.__poroto__上的,而这个属性有个constructor属性指向 fn,那么我们就知道这是 fn 函数的原型。
javascript1fn.prototype===boy.__proto__ 2// true
手写 new 功能
知道了原理,那我们可以开始动手了
1.我们需要先定义一个构造函数
javascript1function create(name){ 2 this.name=name 3} 4create.prototype.say=function (){ 5 alert(this.name) 6}
2.创建一个 new 函数,接收构造函数为参数
javascript1function lineNew(func){ 2 const x=Object.create(func.prototype) //创建一个空对象,原型连接到传入的构造函数身上 3 return x //返回一个对象 4}
3.既然内部需要有 name 属性,那我们就需要把 name 传进去,而且需要调用构造函数
javascript1function likeNew(func,...args){ 2 const x=Object.create(func.prototype) 3 func.call(x,...args) 4 return x 5}
实验一下:
javascript1const boy=likeNew(create,'qiuyanxi')

看起来没问题。
细节
虽然功能实现了,但是有些细节问题需要处理。
比如说箭头函数是没有 原型的,所以我们可以手动帮它创建一个。
比如说会不会有些人不传函数进去呀?所以我们需要做一点 Polyfill
优化代码
javascript1function likeNew(func,...args){ 2 if(typeof func !=='function'){ 3 throw new Error('first arg is not function') 4 } 5 let x={} 6 if(func.prototype){ 7 x=Object.create(func.prototype) 8 }else{ 9 x.__proto__={constructor:func} //手动创建一个原型接上 10 } 11 func.call(x,...args) 12 return x 13}
构造函数返回对象问题
有时候面试题会问你构造函数返回一个对象,那么 new 会怎么做。
我们直接实验出真知
javascript1function foo(name){ 2 this.name=name; 3 return {age:18} 4} 5const boy=new foo('qiuyanxi') 6boy // {age: 18}
结论:如果构造函数返回了对象,那 new 就返回这个对象,否则就返回 new 自己创建的对象。
这一点 MDN 也有介绍
当代码 new Foo(...) 执行时,会发生以下事情:
1.一个继承自 Foo.prototype 的新对象被创建。 2.使用指定的参数调用构造函数 Foo,并将 this 绑定到新创建的对象。new Foo 等同于 new Foo(),也就是没有指定参数列表,Foo 不带任何参数调用的情况。 3.由构造函数返回的对象就是 new 表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤 1 创建的对象。(一般情况下,构造函数不返回值,但是用户可以选择主动返回对象,来覆盖正常的对象创建步骤)
那么我们继续改一下代码
javascript1function likeNew(func,...args){ 2 if(typeof func !=='function'){ 3 throw new Error('first arg is not function') 4 } 5 let x={} 6 if(func.prototype){ 7 x=Object.create(func.prototype) 8 }else{ 9 x.__proto__={constructor:func} //手动创建一个原型接上 10 } 11 return typeof func.call(x,...args)==='object'?func.call(x,...args):x 12}
一般面试不需要做 Polyfill,这里附上简单的几行代码
javascript1function _new(initFunc, ...rest) { 2 // let xx.__proto__ = initFunc.prototype 3 let cache = Object.create(initFunc.prototype) 4 let result = initFunc.call(cache, ...rest) 5 return typeof result === 'object' ? result : cache 6}
结束~
enjoy!