js-new.target

js-new.target
最新回答
白云下的棉絮

2021-02-14 13:29:40

new.target 是 JavaScript 中的一个元属性,用于检测函数或构造方法是否通过 new 运算符调用。以下是其核心特性和用法的详细说明:

1. 基本功能
  • 检测调用方式:在通过 new 调用的构造函数中,new.target 返回该构造函数的引用;在普通函数调用中,其值为 undefined。示例:function Foo() { if (!new.target) throw "Foo() must be called with new"; console.log("Foo instantiated with new");}Foo(); // 抛出错误: "Foo() must be called with new"new Foo(); // 输出: "Foo instantiated with new"
2. 语法与上下文
  • 语法形式:new.target 由关键字 new、点号和属性名 target 组成。虽然 new. 看似对象属性访问,但实际是语言提供的虚拟上下文,仅在构造调用中有效。
  • 箭头函数例外:箭头函数没有自己的 new.target,会继承外层函数的 new.target 值。示例:function Outer() { const arrow = () => console.log(new.target); arrow(); // 输出: undefined(普通调用) new arrow(); // 报错:arrow is not a constructor}new Outer(); // 输出: Outer{}(指向 Outer 构造函数)
3. 类继承中的行为
  • 直接调用:在类的构造函数中,new.target 指向被 new 直接调用的类(可能是子类)。示例:class A { constructor() { console.log(new.target.name); // 输出实际调用的类名 }}class B extends A {}new A(); // 输出: "A"new B(); // 输出: "B"(即使通过 super() 调用父类构造函数)
  • 类定义输出:new.target 返回的是类定义本身(而非实例),可通过 new.target.name 或直接打印查看。示例:class C { constructor() { console.log(new.target); // 输出类定义 }}class D extends C {}new C(); // 输出: class C { constructor() { ... } }new D(); // 输出: class D extends C { constructor() { super(); } }
4. 实际应用场景
  • 强制使用 new:防止构造函数被误作普通函数调用(如内置类型 Date、Array 的实现)。
  • 工厂模式:根据 new.target 动态返回不同子类实例。示例:class Shape { constructor() { if (new.target === Shape) { throw "Cannot instantiate abstract class Shape"; } }}class Circle extends Shape {}new Shape(); // 报错new Circle(); // 正常
5. 注意事项
  • 非构造函数的限制:普通函数或箭头函数无法通过 new 调用,直接使用 new.target 可能导致语法错误或意外行为。
  • 静态方法中的值:静态方法内的 new.target 指向调用时的构造函数,而非类本身(需结合具体调用方式分析)。
总结

new.target 提供了一种在运行时检测构造调用上下文的机制,尤其适用于类继承和构造函数的设计。通过合理利用,可以增强代码的健壮性(如强制 new 调用)或实现灵活的工厂模式。