利用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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。