最近在使用 Symbol 來作爲惟一值,發現 Symbol 沒法進行 new 操做,只能看成函數使用,只要進行了new 就會發生類型錯誤java
new Symbol()
// error
Uncaught TypeError: Symbol is not a constructor
at new Symbol (<anonymous>)
at <anonymous>:1:1
複製代碼
在不考慮底層實現的狀況下,在代碼層面是否可以實現一個函數只能夠進行調用而不能夠進行 new 操做呢?思考以後以下寫出:node
function disConstructor() {
if (this !== window) {
throw new TypeError(' disConstructor is not a constructor')
}
console.log('gogo go')
}
// 測試結果以下
disConstructor() // gogo go
new disConstructor()
// error
Uncaught TypeError: disConstructor is not a constructor
at new disConstructor (<anonymous>:3:15)
at <anonymous>:1:1
複製代碼
若是使用 nodejs,window 能夠切換爲 global, 代碼運行結果不變,由於對於我的而言沒有適用場景。因而就沒有繼續研究下去,但是最近在重新翻閱 es6 時候發現 new.target這個屬性。es6
new.target屬性容許你檢測函數或構造方法是不是經過new運算符被調用的。
在經過new運算符被初始化的函數或構造方法中,new.target返回一個指向構造方法或函數的引用。在普通的函數調用中,new.target 的值是undefined。bash
這樣的話 咱們的代碼就能夠這樣改成編輯器
function disConstructor() {
// 普通的函數調用中,new.target 的值是undefined。
if (new.target) {
throw new TypeError(' disConstructor is not a constructor')
}
console.log('gogo go')
}
複製代碼
獲得與上述代碼同樣的答案。函數
難道 es6 特意添加的功能僅僅只能用於檢查一下咱們的函數調用方式嗎?
在查閱的過程各類發現了大多數都方案都是用 new.target 寫出只能被繼承的類。相似於實現java的抽象類。測試
class Animal {
constructor(name, age) {
if (new.target === Animal) {
throw new Error('Animal class can`t instantiate');
}
this.name = name
this.age = age
}
// 其餘代碼
...
}
class Dog extends Animal{
constructor(name, age, sex) {
super(name, age)
this.sex = sex
}
}
new Animal()
// error
Uncaught Error: Animal class can`t instantiate
at new Animal (<anonymous>:4:13)
at <anonymous>:1:1
new Dog('mimi', 12, '公')
// Dog {name: "mimi", age: 12, sex: "公"}
複製代碼
可是 java抽象類抽象方法須要重寫,這個是沒有方案的。因而在測試與使用的過程當中,卻意外發現了超類能夠在構造期間訪問派生類的原型,利用起來。this
class Animal {
constructor(name, age) {
console.log(new.target.prototype)
}
// 其餘代碼
...
}
複製代碼
以前運行時調用須要重寫的方法報錯是這樣寫的。spa
class Animal {
constructor(name, age) {
this.name = name
this.age = age
}
getName () {
throw new Error('please overwrite getName method')
}
}
class Dog extends Animal{
constructor(name, age, sex) {
super(name, age)
this.sex = sex
}
}
const pite = new Dog('pite', 2, '公')
a.getName()
// error
Uncaught Error: please overwrite getName method
at Dog.getName (<anonymous>:8:11)
at <anonymous>:1:3
複製代碼
然而此時利用 new.target ,我就能夠利用 構造期間 對子類進行操做報錯。prototype
class Animal {
constructor(name, age) {
// 若是 target 不是 基類 且 沒有 getName 報錯
if (new.target !== Animal && !new.target.prototype.hasOwnProperty('getName')) {
throw new Error('please overwrite getName method')
}
this.name = name
this.age = age
}
}
class Dog extends Animal{
constructor(name, age, sex) {
super(name, age)
this.sex = sex
}
}
const pite = new Dog('pite', 2, '公')
// error
Uncaught Error: please overwrite getName method
at new Animal (<anonymous>:5:13)
at new Dog (<anonymous>:14:5)
at <anonymous>:1:1
複製代碼
此時能夠把運行方法時候發生的錯誤提早到構造時期,雖然都是在運行期,可是該錯誤觸發機制要早危害要大。反而對代碼是一種保護。
固然了,利用超類能夠在構造期間訪問派生類的原型做用遠遠不是那麼簡單,必然是很強大的,能夠結合業務場景談一談理解和做用。
增長 編輯器插件 proxy 修飾器