IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    new做了些什么

    草依山发表于 2017-02-13 13:00:28
    love 0

    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 的代码,可以直译为:

    1. 创建一个以当前 Function 原型为原型的新对象 that
    2. 以 that 作为上下文,当前 Function 接收的参数为参数,执行当前 Function ,得结果记为 other
    3. 如果 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:

    1. Assert: constructProduction is either a NewExpression or a MemberExpression.
    2. Assert: arguments is either empty or an Arguments production.
    3. Let ref be the result of evaluating constructProduction.
    4. Let constructor be ? GetValue(ref).
    5. If arguments is empty, let argList be a new empty List.
    6. Else,
      1. Let argList be ArgumentListEvaluation of arguments.
      2. ReturnIfAbrupt(argList).
    7. If IsConstructor(constructor) is false, throw a TypeError exception.
    8. 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)
    • 调用 IsConstructor(constructor),如果是 false, 抛出一个 TypeError 异常
    • 调用并返回 Construct(constructor, argList)

    重点就在最后两步,其中 IsConstructor 首先判断 constructor 是不是一个对象,然后判断它有没有 [[Construct]] 内置方法, 这个内置方法是在函数初始化的时候绑定的,有些内置函数是没有这个属性的,比如 String.prototype.toString 如果对一个没有这个属性 的对象调用 new 就会抛出一个 TypeError 的错误。

    最后的 Construct 实际比较复杂,在又一次校验过 constructor 后,会调用 [[construct]] ,这里调用的又分为两种,一种是普通的函数对象,另外一种是 内置的函数对象

    重点看一下第一种的情况,实质就是如果是普通的函数,设置执行上下文,执行函数体, 如果有返回值,且返回值是对象,直接返回对象,如果返回 undefined, 抛出 TypeError,最后是返回正常绑定的 this

    最后这一点涉及的分支还是有几个,我就不继续对着文档解读了,困。。。

    相对于 ES5 真的复杂了太多!

    参考:

    • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new

    文章来源: new做了些什么
    文章的标签: javascript


沪ICP备19023445号-2号
友情链接