大家好,我是前端西瓜哥。JS装饰器还在提案中(提了很久),还没有进入官方标准。掌握半成品不划算。但是装饰器实在是太强大了。TypeScript仍然在第一个版本的基础上实现了自己的装饰器特性,并将其标记为实验性的,以便大家早日使用。目前很多知名的第三方库(如Nest.js)都使用了TS装饰器,学习还是很有必要的。然而,TS的装饰器实现已经与ECMAScript的装饰器提案相去甚远。但由于TS装饰器被许多知名的第三方库使用,我们可能仍然需要使用与标准不同的装饰器。以后两个装饰器的实现打架,太乱了,估计库作者要吐槽了。TS中实现的装饰器有:classdecoratormethoddecoratoraccessordecoratorpropertydecoratorparameterdecorator在使用类装饰器之前,需要在tsconfig.json中启用experimental装饰器配置:{"compilerOptions":{"experimentalDecorators":true}}一个装饰器是实际上是一个需要在被类使用之前声明的函数。因为装饰器会在类声明后立即执行,如果没有提前声明,会报错。类装饰器类装饰器是一个函数,可以在声明类时获取类,然后对类进行一些操作。将类装饰器应用于类的方法是在类名上方的行中添加@<装饰器名称>。functionchangeDefaultPrice(constructor:Function&{defaultPrice:number}){constructor.defaultPrice=100;}@changeDefaultPriceclassWatermelon{staticdefaultPrice=9;}Watermelon.defaultPrice上面代码可以看到,Watermelon类有一个静态属性defaultPrice,值为9,表示默认的西瓜只要9元。它太便宜了,所以我实现了一个changeDefaultPrice装饰器,它从函数参数中获取类并将其修改为$100。有时我们希望能够修改为自定义价格。这时候我们就可以使用装饰器工厂功能。所谓装饰器工厂函数就是返回一个装饰器函数的函数。通过它,我们可以使用闭包注入变量。functionchangeDefaultPrice(price=100){returnfunction(constructor:Function&{defaultPrice:number}){constructor.defaultPrice=price;};}@changeDefaultPrice(50)classWatermelon{staticdefaultPrice=9;}Watermelon.defaultPrice装饰工厂函数不仅可以用在类装饰器中,也可以用在其他类型的装饰器中。方法装饰器方法装饰器接受的参数有:target:类或类的原型对象。以下代码获取Watermelon.prototype。如果修饰static标识的方法,就得到类。prop:方法名,以下代码获取“say”字符串。descriptor:prop的描述符,我们可以直接修改这个对象,然后这个对象会被装饰器重新应用到这个属性上。functionchangeMethod(target:any,prop:string|symbol,descriptor:PropertyDescriptor){descriptor.value=function(){console.log("我没破解");};}classWatermelon{@changeMethodsay(){console.log("我崩溃了");}}constwm=newWatermelon();wm.say();上面的代码用changeMethod方法装饰器覆盖了Watermelon.prototype.say方法。如果TS编译失败,需要在tsconfig.json中配置target,使其大于等于ES5版本。默认ES3版本不支持某些API。Accessor装饰器Accessor装饰器,用来装饰类的get或set方法。与方法装饰器类似,访问器装饰器获取的参数是:target:类或类的原型对象。prop:成员名称。descriptor:成员的描述符。functiondoublePrice(target:Object,prop:string|symbol,descriptor:PropertyDescriptor){constgetter=descriptor.get!;descriptor.get=function(){returngetter.call(this)*2;}}类西瓜{private_price=9;@doublePricegetprice(){returnthis._price;}}constwm=newWatermelon();wm.price上面的代码将price的值加倍。属性装饰器属性装饰器,顾名思义,就是用来修饰类的属性的。属性装饰器接受的参数有:taget:类或类的原型对象。prop:属性名称。functionpropDeco(target:any,prop:string|symbol){console.log({target,prop});}classWatermelon{@propDecogoodName="Watermelon";}参数装饰器参数装饰器用于装饰函数参数,使用对于类构造函数和方法。参数装饰器可以获得的参数有:target:类或类的原型对象。prop:函数名,或未定义(当函数是构造函数时)。paramIdx:被修饰参数的位置。functionvalidatePhone(target:Object,prop:string|symbol,paramIdx:number){}classWatermelon{构造函数(a:string,@validatePhoneb:string){console.log(a,b);}}parameterdecorator一个目的是做参数校验,保存某个索引的位置,然后用methoddecorator获取descriptor描述符,把原来的方法封装一层校验。总结一般情况下,TS装饰器可以给类加上一些标签,然后相应的装饰器就可以获得必要的信息(类原型、方法名、描述符等),进而可以做一些代理和记录信息的增强。TS装饰器编译出来的最终JS会丢掉这些装饰器标签,其实本质上就是语法糖。我是前端西瓜哥,欢迎关注我,学习更多前端知识。
