什么是“新目标”

What is "new.target"?

本文关键字:新目标 目标 什么      更新时间:2023-09-26

ECMAScript 2015规范提到关键字new。目标正好3次- 1次在14.2.3:

通常情况下,Contains不会查看大多数函数形式的内部。Contains用于检测new。Target 、this和super在对象中的用法ArrowFunction .

和14.2.16中的两次:

ArrowFunction没有为arguments、super、this或new.target。任何对参数,super, this, or的引用新。ArrowFunction中的target必须解析为类中的绑定词法封闭环境

MDN提到了它,但非常模糊,页面不完整。

Babel似乎不支持它。当尝试使用new时,我得到了语法错误。函数中的目标(箭头或其他)。

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

您在规范中找不到它,因为在语法定义中它是用空白书写的,如new . target。这个表达式的名字是NewTarget,你会发现这个词出现了好几次。

NewTarget是第一个所谓的元属性,可以在§12.3.8中找到。

它的唯一目的是检索当前(非箭头)函数环境的[[NewTarget]]值的当前值。它是一个函数被调用时设置的值(非常像this绑定),并且根据§8.1.1.3 函数环境记录:

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

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

但这不是它的真正目的。那么它是什么呢?这是ES6类不仅是语法糖的一部分,也是它们允许我们继承内置对象的一部分。当你通过new X调用class构造函数时,this的值还没有初始化——当进入构造函数体时,对象还没有被创建。它确实是在super()调用期间由超级构造函数创建的(这在应该创建内部槽时是必要的)。但是,实例应该继承最初调用的构造函数的.prototype,这就是newTarget发挥作用的地方。它保留在super()调用期间接收new调用的"最外层"构造函数。你可以在规范中一直遵循它,但基本上它总是newTarget而不是当前执行的构造函数被传递到OrdinaryCreateFromConstructor过程中-例如在§9.2.2 [[Construct]]的第5步中对于用户定义的函数。

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

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;

这主要是为了更好地检测没有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