new.target 属性

new是从构造函数生成实例对象的命令。ES6 为new命令引入了一个new.target属性,该属性一般用在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令或Reflect.construct()调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。

  1. function Person(name) {
  2. if (new.target !== undefined) {
  3. this.name = name;
  4. } else {
  5. throw new Error('必须使用 new 命令生成实例');
  6. }
  7. }
  8. // 另一种写法
  9. function Person(name) {
  10. if (new.target === Person) {
  11. this.name = name;
  12. } else {
  13. throw new Error('必须使用 new 命令生成实例');
  14. }
  15. }
  16. var person = new Person('张三'); // 正确
  17. var notAPerson = Person.call(person, '张三'); // 报错

上面代码确保构造函数只能通过new命令调用。

Class 内部调用new.target,返回当前 Class。

  1. class Rectangle {
  2. constructor(length, width) {
  3. console.log(new.target === Rectangle);
  4. this.length = length;
  5. this.width = width;
  6. }
  7. }
  8. var obj = new Rectangle(3, 4); // 输出 true

需要注意的是,子类继承父类时,new.target会返回子类。

  1. class Rectangle {
  2. constructor(length, width) {
  3. console.log(new.target === Rectangle);
  4. // ...
  5. }
  6. }
  7. class Square extends Rectangle {
  8. constructor(length, width) {
  9. super(length, width);
  10. }
  11. }
  12. var obj = new Square(3); // 输出 false

上面代码中,new.target会返回子类。

利用这个特点,可以写出不能独立使用、必须继承后才能使用的类。

  1. class Shape {
  2. constructor() {
  3. if (new.target === Shape) {
  4. throw new Error('本类不能实例化');
  5. }
  6. }
  7. }
  8. class Rectangle extends Shape {
  9. constructor(length, width) {
  10. super();
  11. // ...
  12. }
  13. }
  14. var x = new Shape(); // 报错
  15. var y = new Rectangle(3, 4); // 正确

上面代码中,Shape类不能被实例化,只能用于继承。

注意,在函数外部,使用new.target会报错。