什么是“new.target”?

IT技术 javascript ecmascript-6
2021-02-08 17:32:44

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

通常,Contains 不会查看大多数函数形式的内部。但是,Contains 用于检测ArrowFunction 中的 new.target、 this 和 super 用法。

14.2.16 中两次

ArrowFunction 没有为参数、super、this 或new.target定义本地绑定ArrowFunction 中对参数、super、this 或new.target 的任何引用 都必须解析为词法封闭环境中的绑定

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

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

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

2个回答

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

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

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

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

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

但这不是它的真正目的。那么到底是什么呢?ES6 类不仅是语法糖,也是它们如何允许我们从内置对象继承的方式的一部分。当您class通过调用构造函数时new X,该this值尚未初始化 - 输入构造函数主体时尚未创建对象。它确实在super()调用期间由超级构造函数创建(当应该创建内部插槽时这是必需的)。尽管如此,该实例应该继承自.prototype最初调用的构造函数的 ,这就是newTarget发挥作用的地方。它确实保存了在new调用期间接收调用的“最外层”构造函数super()调用。您可以在规范中一直遵循它,但基本上它总是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;
@Maximus不是一个孩子,但 Child 构造函数本身。我们希望新实例继承自Child.prototype对象
2021-03-16 17:32:44
所以这意味着它console.log(new . target)在函数内写入(带空格)的有效语法
2021-03-17 17:32:44
但那不完全一样。console是标识符,new是关键字。当考虑new Obj()有效语法时,这会变得很奇怪
2021-03-21 17:32:44
@Amit:我认为 - 它是多个标记,始终可以通过空格分隔。编写 ES 也是有效的console . log(…):-) 当然没有人这样做 - 除了方法链接时的换行符......
2021-03-28 17:32:44
@Asad:您无法thissuper()调用之前访问- 当您尝试引用它时,它会抛出一个ReferenceError.
2021-04-07 17:32:44

它的主要目的是作为一种更好的方法来检测何时调用构造函数而没有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”调用的常规函数​​,否则我只是误解了你。
2021-03-16 17:32:44
@Asad 构造函数一个用 调用的常规函数new
2021-03-27 17:32:44
规范中在哪里定义了这些?
2021-04-03 17:32:44
@Amit 我说的是经典意义上的构造函数function Foo()
2021-04-03 17:32:44
我知道了。我是在新的 ES6constructor关键字构造函数的意义上考虑它的,如果您不使用new.
2021-04-08 17:32:44