es 6 new.targetを利用して模擬抽象類に対して

3716 ワード

起源
最近はSymbolを唯一の値として使っていますが、Symbolはnew操作ができず、関数としてしか使えないので、newを行うとタイプエラーが発生します.
new Symbol()

// error
Uncaught TypeError: Symbol is not a constructor
    at new Symbol ()
    at :1:1
下の実装を考慮しないで、コードレベルでは、new操作ではなく一つの関数だけを呼び出してもいいですか?考えた後、次のように書きます.
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 (:3:15)
    at :1:1
nodejsを使えば、windowはglobalに切り替わります.コードの運行結果は変わりません.個人には適用シーンがないからです.そこで研究を続けていませんでしたが、最近は新しくページをめくる際にnew.targetという属性を発見しました.
new.target属性
紹介(mdn文書参照)
new.target属性は、関数または構造方法がnew演算子で呼び出されたかどうかを検出することができます.new演算子によって初期化された関数または構造方法では、new.targetは、構造方法または関数への参照を返します.通常の関数呼び出しでは、new.targetの値はundefinedです.
このようにすれば、私たちのコードはこのように変更できます.
function disConstructor() {
  //         ,new.target    undefined。
  if (new.target) {
    throw new TypeError(' disConstructor is not a constructor')
  }
  console.log('gogo go')
}
上記のコードと同じ答えを得ました.
深く入り込む
エス6がわざわざ追加した機能は私達の関数の呼び方を確認するだけですか?調べていくうちに、ほとんどの案は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 (:4:13)
    at :1:1

new Dog('mimi', 12, ' ')
// Dog {name: "mimi", age: 12, sex: " "}
しかし、javaの抽象的な方法は書き換える必要があります.これは無案です.そこで、テストと使用の過程で、意外にも超種類が構造中に派生類の原型にアクセスできることを発見し、利用してきました.
class Animal {
  constructor(name, age) {
    console.log(new.target.prototype)
  }
  //     
  ...
}
前の運転時に呼び出して書き直す方法を間違えて書きました.
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 (:8:11)
    at :1:3
しかし、この時はnew.targetを利用して、構造期間を利用してサブクラスを操作してエラーを報告することができます.
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 (:5:13)
    at new Dog (:14:5)
    at :1:1
この時、運転方法の時に発生したエラーを構造時期まで繰り上げることができます.全部運行期間ですが、このエラートリガメカニズムは早期に危害がかかります.むしろコードは保護されています.
もちろん、超種類を利用して、構造期間中に派生類の原型にアクセスできるのはそんなに簡単ではありません.きっと強いです.業務シーンに合わせて、理解と役割を話してもいいです.
その他の案
エディタプラグインproxyを追加します.