利用ES6中class裏的new.target屬性寫出不能獨立使用、必須繼承後才能使用的類

new.target屬性

  • new是從構造函數生成實例對象的命令。ES6 爲new命令引入了一個new.target屬性,該屬性一般用在構造函數之中,返回new命令作用於的那個構造函數。如果構造函數不是通過new命令或Reflect.construct()調用的,new.target會返回undefined,因此這個屬性可以用來確定構造函數是怎麼調用的。
function Person(name) {
  if (new.target !== undefined) {
    this.name = name;
  } else {
    throw new Error('必須使用 new 命令生成實例');
  }
}

// 另一種寫法
function Person(name) {
  if (new.target === Person) {
    this.name = name;
  } else {
    throw new Error('必須使用 new 命令生成實例');
  }
}

var person = new Person('張三'); // 正確
var notAPerson = Person.call(person, '張三');  // 報錯

上面代碼確保構造函數只能通過new命令調用。

  • Class 內部調用new.target,返回當前 Class。
class Rectangle {
  constructor(length, width) {
    console.log(new.target === Rectangle);
    this.length = length;
    this.width = width;
  }
}

var obj = new Rectangle(3, 4); // 輸出 true
  • 需要注意的是,子類繼承父類時,new.target會返回子類。
class Rectangle {
  constructor(length, width) {
    console.log(new.target === Rectangle);
    // ...
  }
}

class Square extends Rectangle {
  constructor(length) {
    super(length, width);
  }
}

var obj = new Square(3); // 輸出 false

上面代碼中,new.target會返回子類。

  • 利用這個特點,可以寫出不能獨立使用、必須繼承後才能使用的類。
class Shape {
  constructor() {
    if (new.target === Shape) {
      throw new Error('本類不能實例化');
    }
  }
}

class Rectangle extends Shape {
  constructor(length, width) {
    super();
    // ...
  }
}

var x = new Shape();  // 報錯
var y = new Rectangle(3, 4);  // 正確

上面代碼中,Shape類不能被實例化,只能用於繼承。

注意,在函數外部,使用new.target會報錯。

拓展:

  • Object.getPrototypeOf()

Object.getPrototypeOf方法可以用來從子類上獲取父類。

Object.getPrototypeOf(Rectangle) === Shape
// true

因此,可以使用這個方法判斷,一個類是否繼承了另一個類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章