new做了些什么
new
操作符,熟悉又陌生,昨晚翻看了一下《Javascript语言精粹》,47页有一段代码说的是 new
执行的过程,代码如下:
Function.method('new',function(){
var that = Object.beget(this.prototype)
var other = this.apply(that, arguments)
return (typeof other === 'object' && other ) || that
})
其中的 method
是 Function
原型上的一个方法,方便给 Function
原型上加方法,
Object.beget
方法可以理解为返回一个使用 this.prototype
作为其原型的新对象,
这个方法对应的其实是 Object.create
。
两者的代码如下
if(typeof Object.beget !== 'function') {
Object.beget = function(o){
var F = function(){}
F.prototype = o
return new F()
}
}
Function.prototype.method = function(name, func) {
if(!this.prototype[name]) {
this.prototype[name] = func
}
}
老道的那段解释 new
的代码,可以直译为:
- 创建一个以当前
Function
原型为原型的新对象that
- 以
that
作为上下文,当前Function
接收的参数为参数,执行当前Function
,得结果记为other
- 如果
other
为一个对象返回它,否则返回that
那么规范里的 new
是按规定是怎么执行的呢?请看这里,摘抄如下:
12.3.3.1 Runtime Semantics: Evaluation
- NewExpression : new NewExpression
- Return ? EvaluateNew(NewExpression, empty).
- MemberExpression : new MemberExpression Arguments
- Return ? EvaluateNew(MemberExpression, Arguments).
12.3.3.1.1 Runtime Semantics: EvaluateNew(constructProduction, arguments)
The abstract operation EvaluateNew with arguments constructProduction, and arguments performs the following steps:
- Assert: constructProduction is either a NewExpression or a MemberExpression.
- Assert: arguments is either empty or an Arguments production.
- Let ref be the result of evaluating constructProduction.
- Let constructor be ? GetValue(ref).
- If arguments is empty, let argList be a new empty List.
- Else,
- Let argList be ArgumentListEvaluation of arguments.
- ReturnIfAbrupt(argList).
- If IsConstructor(constructor) is false, throw a TypeError exception.
- Return ? Construct(constructor, argList).
简单解释下,new
有两种,一种是带参数的,一种不带参数的,其中 NewExpression 和 MemberExpression
我们先跳过,这是两种表达式,它们包含的种类非常多,我们直接看 EvaluateNew
里的过程
- 首先断定 表达式要么是
NewExpression
要么是MemberExpression
- 断定
arguments
要么是 空, 要么是Arguments production
- 设 ref 为表达式执行的结果
- 设 constructor 为
GetValue(ref)
的值 - 如果
arguments
是空,设 argList 为一个空的List
- 不为空
- 设 argList 为
arguments
的ArgumentListEvaluation
- 调用
ReturnIfAbrupt(argList)
- 设 argList 为
- 调用
IsConstructor(constructor)
,如果是 false, 抛出一个TypeError
异常 - 调用并返回
Construct(constructor, argList)
重点就在最后两步,其中 IsConstructor
首先判断 constructor 是不是一个对象,然后判断它有没有 [[Construct]]
内置方法,
这个内置方法是在函数初始化的时候绑定的,有些内置函数是没有这个属性的,比如 String.prototype.toString
如果对一个没有这个属性
的对象调用 new 就会抛出一个 TypeError
的错误。
最后的 Construct
实际比较复杂,在又一次校验过
constructor 后,会调用 [[construct]]
,这里调用的又分为两种,一种是普通的函数对象,另外一种是
内置的函数对象
重点看一下第一种的情况,实质就是如果是普通的函数,设置执行上下文,执行函数体,
如果有返回值,且返回值是对象,直接返回对象,如果返回 undefined, 抛出 TypeError
,最后是返回正常绑定的 this
最后这一点涉及的分支还是有几个,我就不继续对着文档解读了,困。。。
相对于 ES5 真的复杂了太多!
参考: