javascript new.target的学习笔记
作者:明长歌
new.target
new.target
是一个元属性(meta property),在ECMAScript 2015 (ES6) 中引入,用于检测函数是否通过 new
关键字调用。简单来说,当一个函数用 new
关键字调用时,new.target
会指向这个函数本身;如果函数是直接调用,new.target
的值则为 undefined
。
function Foo() { console.log('new.target',new.target) console.log('new.target.prototype',new.target.prototype) if (!new.target) { throw new TypeError("calling Foo constructor without new is invalid"); } } try { new Foo(); Foo(); } catch (e) { console.log(e); // Expected output: TypeError: calling Foo constructor without new is invalid } // 输出: /* "new.target" function Foo() { console.log('new.target',new.target) console.log('new.target.prototype',new.target.prototype) if (!new.target) { throw new TypeError("calling Foo constructor without new is invalid"); } } "new.target.prototype" Object { } */ /* "new.target" undefined TypeError: Cannot read properties of undefined (reading 'prototype') */
值
new.target 保证是一个可构造的函数值或 undefined。
在类构造函数中,它指向 new
调用的类,这可能是当前构造函数的子类,因为子类通过 super()
传递调用了父类的构造函数。
在父类的构造函数里,new.target 并不等于父类本身,而是“真正被 new 的那个类”——往往正是它的某个子类。因为子类在构造时要先 super(),于是父类构造函数的 new.target 就指向了子类。
class Animal{ constructor() { console.log('Animal -> new.target.name:', new.target.name); } } class Dog extends Animal{ constructor() { super(); console.log('Dog -> new.target.name:', new.target.name); } } class toyDog extends Dog{ constructor() { super(); console.log('ToyDog -> new.target.name:', new.target.name); } } new Dog(); // Animal -> new.target.name: Dog // Dog -> new.target.name: Dog console.log('----------------'); new toyDog(); // Animal -> new.target.name: toyDog // Dog -> new.target.name: toyDog // ToyDog -> new.target.name: toyDog
在普通函数中,如果函数是直接通过 new
构造的,则 new.target
指向函数本身。如果函数不是通过 new
调用的,则 new.target
是 undefined
。函数可以被用作 extends
的基类,这种情况下 new.target
可能指向子类。
function Foo(msg) { console.log(msg, '--new.target =', new.target); } // 通过 `new` 构造的,则 `new.target` 指向函数本身 new Foo('new Foo'); /* 输出:new Foo --new.target = ƒ Foo(msg) { console.log(msg, '--new.target =', new.target); } */ // 不是通过 `new` 调用的,则 `new.target` 是 `undefined` Foo('call Foo'); /* 输出:call Foo --new.target = undefined */ // 函数可以被用作 `extends` 的基类,这种情况下 `new.target` 可能指向子类。 class Bar extends Foo { constructor() { super('new Bar'); } } new Bar(); /* 输出:new Bar --new.target = class Bar extends Foo { constructor() { super('new Bar'); } } */
如果构造函数(类或者函数)是通过 Reflect.construct()
调用的,那么 new.target
指向作为 newTarget
传递的值(默认为 target
)。
function One(name) { this.name = name; console.log('One -> new.target.name:', new.target.name); } const obj=Reflect.construct(One, ['aa'], Array); console.log(obj); // 输出:Array {name: 'aa'} console.log('obj instanceof One:', obj instanceof One); // 输出:obj instanceof One: false console.log('obj instanceof Array:', obj instanceof Array); // 输出:obj instanceof Array: true
在箭头函数中,new.target
是从周围的作用域继承的。如果箭头函数不是在另一个具有 new.target
绑定的类或函数中定义的,则会抛出语法错误。
class A { constructor() { const arrow = () => console.log('new.target →', new.target); arrow(); // 箭头函数继承自构造函数作用域 } } class B extends A {} new B(); //输出:new.target → class B extends A {}
// 在全局作用域里 const arrow = () => { console.log(new.target); // 报错:ReferenceError }; arrow(); //输出报错:Uncaught SyntaxError: new.target expression is not allowed here
在静态初始化块中,new.target
是 undefined
class WithStatic { static { console.log('Static block new.target:', new.target); // undefined } } new WithStatic(); // 输出:Static block new.target: undefined
参考:
到此这篇关于javascript new.target的学习笔记的文章就介绍到这了,更多相关javascript new.target内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!