“;新的“;关键字工作,如ECMAScript 5标准中所述

How does the "new" keyword work as described in ECMAScript 5 standard

本文关键字:标准 新的 关键字 工作 ECMAScript      更新时间:2023-09-26

我想知道new运算符是如何工作的,而不仅仅是学习如何使用它。我查看了ECMAScript 5标准,发现算法描述了它的工作方式,但对它的含义有点困惑。

生产NewExpression : new NewExpression评估为如下:

  1. ref为NewExpression的求值结果
  2. constructor为GetValue(ref)
  3. 如果Type(constructor)不是Object,则引发TypeError异常
  4. 如果constructor未实现[[Construct]]内部方法,则引发TypeError异常
  5. 返回在constructor上调用[[Construct]]内部方法的结果,不提供任何参数(即参数的空列表)

我试着用这个例子来理解上面的算法:

var f = function() {};    
var h = new f();

特别是我不理解第一步,因此无法遵循其他步骤。

  1. 设CCD_ 13为NewExpression的求值结果
var h = new f();
        ~~~ ~~~~
         |    '_________ NewExpression 
     new operator

这是否意味着reff()的值?但它是undefined

3。如果Type(constructor)不是Object,则抛出TypeError异常。

但是f的类型是函数,它会抛出TypeError异常吗?

5。返回在constructor上调用[[Construct]]内部方法的结果,不提供任何参数(即参数的空列表)。

[[Construct]]函数的内部属性,在constructor上调用它有什么意义?

首先,我们必须澄清什么是new NewExpression,尤其是NewExpression。这可以在附录A中找到。应用此规则的最常见情况是当您不将参数传递给构造函数时。即

var obj = new F;

其中CCD_ 28是指函数。这就是让你省略括号的规则。

在您的示例(var h = new f();)中,您有括号,即您传递的是一个空的参数列表,因此此算法不适用。f()而不是NewExpression

相反,此算法适用于:new MemberExpression Arguments。它的评估方式几乎相同,算法也可以在§11.2.2中找到,就在你引用的算法之后。

考虑到这一点,让我们一步一步地研究该算法:

1.设CCD_ 33是对CCD_。

在您的示例中,MemberExpressionf,即它是一个变量。评估的结果是一个特殊的参考对象。这里并不重要它到底是什么。只要知道它包含关于如何从变量中实际获取值的信息
所以现在ref引用了这个引用。

2.设constructorGetValue(ref)

这是指实际检索到变量的值,并且constructor将引用f所引用的函数。

3.设argList是评估Arguments的结果,生成参数值的内部列表(11.2.4)

在您的情况下,Arguments(),因此它是一个空列表。

4.如果Type(constructor)不是Object,则抛出TypeError异常。

重要的是要知道函数也是对象!因此,如果在new表达式中使用基元值,则此步骤将抛出错误。

5.如果constructor没有实现[[Construct]]内部方法,则抛出TypeError异常。

所有函数(以及潜在的其他对象)都实现了一个内部[[Construct]]属性,该属性对新对象进行实际实例化。如果对象没有这样的属性,则不能将其用作构造函数。第13.2.2节对其功能工作方式进行了定义。

6.返回调用构造函数上的[[Construct]]内部方法的结果,提供列表argList作为参数值。

这是实际施工的情况。[[Construct]]本身就是一种功能,其定义见§13.2.2。该方法与每个函数相同,负责创建一个新对象,在该新对象上调用函数并返回它或函数返回的任何内容。

以下是它在JavaScript中的外观示例(部分是伪代码):

[[Construct]] = function(F, argList) {
    // Create new object that in inherits from F.prototype or Object.prototype
    var proto = F.prototype;
    var obj = Object.create(typeof proto === 'object' ? proto : Object.prototype);
    // Call F with this set to obj and pass the argument list
    var result = F.apply(obj, argList);
    // If result is not an object, return the generated object
    return typeof result === 'object' ? result : obj;
};

让我们一步一步地进行

  1. 解决类似new window['foo' + 1 + 'bar']->new window.foo1bar的问题
  2. 确定实际引用的对象:什么是window?全局对象的局部变量或属性
  3. 这是显而易见的
  4. 不那么明显,但重点是:每个Function都是构造函数,但不是每个构造函数都是Function。这一点确保了new只在构造函数上被调用
  5. 运行构造函数。请注意,规范还为new foo(...)提供了MemberExpression : new MemberExpression Arguments