利用es6 new.target来对模拟抽象类的方法
起源
最近在使用Symbol来做为唯一值,发现Symbol无法进行new操作,只能当作函数使用,只要进行了new就会发生类型错误
newSymbol() //error UncaughtTypeError:Symbolisnotaconstructor atnewSymbol() at :1:1
在不考虑底层实现的情况下,在代码层面是否能够实现一个函数只可以进行调用而不可以进行new操作呢?思考之后如下写出:
functiondisConstructor(){
if(this!==window){
thrownewTypeError('disConstructorisnotaconstructor')
}
console.log('gogogo')
}
//测试结果如下
disConstructor()//gogogo
newdisConstructor()
//error
UncaughtTypeError:disConstructorisnotaconstructor
atnewdisConstructor(:3:15)
at:1:1
如果使用nodejs,window可以切换为global,代码运行结果不变,因为对于个人而言没有适用场景。于是就没有继续研究下去,可是最近在从新翻阅es6时候发现new.target这个属性。
new.target属性
介绍(引用mdn文档)
new.target属性允许你检测函数或构造方法是否是通过new运算符被调用的。
在通过new运算符被初始化的函数或构造方法中,new.target返回一个指向构造方法或函数的引用。在普通的函数调用中,new.target的值是undefined。
这样的话我们的代码就可以这样改为
functiondisConstructor(){
//普通的函数调用中,new.target的值是undefined。
if(new.target){
thrownewTypeError('disConstructorisnotaconstructor')
}
console.log('gogogo')
}
得到与上述代码一样的答案。
深入
难道es6特地添加的功能仅仅只能用于检查一下我们的函数调用方式吗?
在查阅的过程各种发现了大多数都方案都是用new.target写出只能被继承的类。类似于实现java的抽象类。
classAnimal{
constructor(name,age){
if(new.target===Animal){
thrownewError('Animalclasscan`tinstantiate');
}
this.name=name
this.age=age
}
//其他代码
...
}
classDogextendsAnimal{
constructor(name,age,sex){
super(name,age)
this.sex=sex
}
}
newAnimal()
//error
UncaughtError:Animalclasscan`tinstantiate
atnewAnimal(:4:13)
at:1:1
newDog('mimi',12,'公')
//Dog{name:"mimi",age:12,sex:"公"}
但是java抽象类抽象方法需要重写,这个是没有方案的。于是在测试与使用的过程中,却意外发现了超类可以在构造期间访问派生类的原型,利用起来。
classAnimal{
constructor(name,age){
console.log(new.target.prototype)
}
//其他代码
...
}
之前运行时调用需要重写的方法报错是这样写的。
classAnimal{
constructor(name,age){
this.name=name
this.age=age
}
getName(){
thrownewError('pleaseoverwritegetNamemethod')
}
}
classDogextendsAnimal{
constructor(name,age,sex){
super(name,age)
this.sex=sex
}
}
constpite=newDog('pite',2,'公')
a.getName()
//error
UncaughtError:pleaseoverwritegetNamemethod
atDog.getName(:8:11)
at:1:3
然而此时利用new.target,我就可以利用构造期间对子类进行操作报错。
classAnimal{
constructor(name,age){
//如果target不是基类且没有getName报错
if(new.target!==Animal&&!new.target.prototype.hasOwnProperty('getName')){
thrownewError('pleaseoverwritegetNamemethod')
}
this.name=name
this.age=age
}
}
classDogextendsAnimal{
constructor(name,age,sex){
super(name,age)
this.sex=sex
}
}
constpite=newDog('pite',2,'公')
//error
UncaughtError:pleaseoverwritegetNamemethod
atnewAnimal(:5:13)
atnewDog(:14:5)
at:1:1
此时可以把运行方法时候发生的错误提前到构造时期,虽然都是在运行期,但是该错误触发机制要早危害要大。反而对代码是一种保护。
当然了,利用超类可以在构造期间访问派生类的原型作用远远不是那么简单,必然是很强大的,可以结合业务场景谈一谈理解和作用。
其他方案
- 增加编辑器插件
- proxy
- 修饰器
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。