【问题标题】:What is "new.target"?什么是“new.target”?
【发布时间】:2015-12-03 17:00:39
【问题描述】:

ECMAScript 2015 规范提到关键字(或词?)new.target 恰好 3 次 - 1 次在 14.2.3

通常情况下,Contains 不会查看大多数函数形式的内部但是, Contains 用于检测 new.target、this 和 super 使用情况 箭头函数。

两次14.2.16:

ArrowFunction 没有为参数、super、 这个,或 new.target。任何对参数、super、this 或 ArrowFunction 中的 new.target 必须解析为 词法封闭环境

MDN提到了,但是很模糊,页面不完整。

Babel 似乎不支持它。尝试在函数(箭头或其他)中使用 new.target 时出现语法错误。

它是什么,应该如何使用?

【问题讨论】:

    标签: javascript ecmascript-6


    【解决方案1】:

    您在规范中没有找到它,因为在语法定义中它是用空格编写的,如new . target。表达式的名称是 NewTarget,您会多次找到该术语。

    NewTarget 是所谓的meta properties 中的第一个,可以在 §12.3.8 中找到。

    它的唯一目的是retrieve当前(非箭头)函数环境的[[NewTarget]]值的当前值。它是在调用函数时设置的值(非常类似于this 绑定),并且根据§8.1.1.3 Function Environment Records

    如果这个环境记录是由[[Construct]]内部方法创建的,[[NewTarget]]就是[[Construct]的值] newTarget 参数。否则,其值为undefined

    因此,最终使我们能够检测一个函数是否作为构造函数被调用。

    但这不是它的真正目的。那么它是什么呢?这是 ES6 类不仅是语法糖,而且它们允许我们从内置对象继承的方式的一部分。当您通过new X 调用class 构造函数时,this 值尚未初始化 - 进入构造函数主体时尚未创建对象。它确实是由超级构造函数在super() 调用期间创建的(这在应该创建内部插槽时是必需的)。不过,该实例应该从最初调用的构造函数的.prototype 继承,这就是 newTarget 发挥作用的地方。它确实包含在super() 调用期间接收到new 调用的“最外层”构造函数。您可以在规范中一直遵循它,但基本上它始终是 newTarget 而不是当前执行的构造函数,它确实被传递到 OrdinaryCreateFromConstructor procedure - 例如在 step 5 of §9.2.2 [[Construct]] 中用于用户定义的函数。

    长文本,也许一个例子更适合:

    class Parent {
        constructor() {
            // implicit (from the `super` call)
            //    new.target = Child;
            // implicit (because `Parent` doesn't extend anything):
            //    this = Object.create(new.target.prototype);
            console.log(new.target) // Child!
        }
    }
    class Child extends Parent {
        constructor() {
            // `this` is uninitialised (and would throw if accessed)
            // implicit (from the `new` call):
            //    new.target = Child 
            super(); // this = Reflect.construct(Parent, [], new.target);
            console.log(this);
        }
    }
    new Child;
    

    【讨论】:

    • 这意味着在函数中写入console.log(new . target)(带空格)的有效语法?
    • @Amit:我想 - 它是多个标记,总是可以通过空格分隔。写 console . log(…) 也是有效的 ES :-) 当然没有人这样做 - 除了方法链接时的换行符......
    • 但这并不完全相同。 console 是标识符,new 是关键字。当考虑到new Obj() 是有效的语法时,这会很奇怪。
    • @Asad:在super() 调用之前,您无法访问this - 当您尝试引用它时,它会抛出ReferenceError
    • @Maximus 不是 a 孩子,而是 Child constructor 本身。我们希望新实例继承自Child.prototype 对象
    【解决方案2】:

    它的主要目的是作为一种更好的方法来检测在没有new 的情况下调用构造函数。

    来自http://www.2ality.com/2015/02/es6-classes-final.html

    new.target 是所有函数都有的隐式参数。对于构造函数调用就像this 对于方法调用一样。

    所以我可以写:

    function Foo() {
      if (!new.target) throw "Foo() must be called with new";
      ...
    }
    

    这里有更多关于它如何工作的细节,以及更多有用的上下文,但我们将把它留在这里。

    有关new.target 的一些会议记录,请参阅https://esdiscuss.org/notes/2015-01-27

    【讨论】:

    • 我认为没有new 就不可能调用构造函数(你会得到一个异常)。除非“构造函数”是指用“new”调用的常规函数​​,否则我只是误解了你。
    • @Asad 构造函数一个用new调用的常规函数​​。
    • 我明白了。我从新的 ES6 constructor-keyword 构造函数的意义上考虑它,如果你不使用 new 调用它们,则会出现 TypeError。
    • 规范中在哪里定义了这些?
    • @Amit 我说的是经典意义上的构造函数function Foo()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-24
    • 2017-04-21
    • 1970-01-01
    • 2011-04-21
    • 2015-03-21
    • 1970-01-01
    • 2014-07-31
    相关资源
    最近更新 更多