Get to know MDN better
此页面由社区从英文翻译而来。了解更多并加入 MDN Web Docs 社区。
new.target 元属性允许你检测函数或构造函数是否是通过 new 运算符被调用的。在通过 new 运算符执行的函数或构造函数中,new.target 返回一个指向 new 调用的构造函数或函数的引用。在普通的函数调用中,new.target 的值是 undefined。
new.target 保证是一个可构造的函数值或 undefined。
new.target 语法由关键字 new、点和标识符 target 组成。由于 new 是保留字而非标识符;其并不是属性访问器,而是一种特殊的表达式语法。
new.target 元属性在所有的函数/类主体均可用。在函数或类的外部使用 new.target 会导致语法错误。
在普通的函数调用中(和构造函数调用相对),new.target 的值是 undefined。这使得你可以检测一个函数是否是作为构造函数通过 new 被调用的。
在类的构造函数中,new.target 指向直接被 new 执行的构造函数。如果构造函数位于父类中,并且是由子类的构造函数委托的,情况也是如此。new.target 指向被 new 所调用的类。例如,当通过 new B() 初始化 b 时,打印出了 B 的名称;类似地,对于 a,打印出了类 A 的名称。
在 Reflect.construct() 和类出现之前,通常通过传递 this 的值,并让基类构造函数对其进行更改来实现继承。
然而,call() 和 apply() 实际上是对函数进行调用而非构造,所以 new.target 的值是 undefined。这意味着如果 Base() 检查它是否是通过 new 构造的,将会抛出错误(或者可能表现出其他意外的行为)。例如,你不能通过这种方式扩展 Map,因为 Map() 构造函数不能在不使用 new 的情况下调用。
所有内置构造函数都通过读取 new.target.prototype 直接构造新实例的整个原型链。因此,为了确保(1)Base 是通过 new 构造的,以及(2)new.target 指向子类而不是 Base 本身,我们需要使用 Reflect.construct()。
备注:实际上,由于缺少 Reflect.construct(),在转译为 ES6 以前的代码时,无法正确地对内置对象进行子类化(例如 Error 子类化)。
但是,如果你正在编写 ES6 代码,最好使用类和 extends,因为它更易读且更少出错。
| ECMAScript® 2027 Language Specification # sec-built-in-function-objects |
启用 JavaScript 以查看此浏览器兼容性表。