赞
踩
装饰器在其他语言比如Python、Java中早就存在了。而在JavaScript中,直到目前仍处于stage2阶段的提案,这表示虽然未来应该会成为语言的一部分,但现在浏览器或Node都还不支持该特性,必须依赖于转译器。
修饰器(Decorator)是一个函数,用来修改类的行为。这是ES7的一个提案,目前Babel转码器已经支持。
在不改变原对象的基础上,为对象动态地增加职责的方式称为装饰者模式。
出现装饰器的原因:
装饰器优点:
我们如果要设计一个穿搭的应用程序。主题以人这个类为基础。
春夏秋冬我们的衣服穿搭是不一样的。
夏天:在人物类型上,搭配短裤短袖。
秋天:在人物类型上,搭配长裤、长袖、外套
冬天:在人物类型上,搭配羽绒服、冲锋衣、毛衣等等
搭配的服饰肯定不属于人物类型身体的一部分。我可以根据天气随意给人物类型搭配服饰。并且同一件服饰还可以给不同的人物搭配。或者同一个人物类型还可以搭配多种服饰。可以随意搭配、随意脱掉。
人物类型确定过后,服饰搭配就是我们需要给人物进行装饰。这个过程映射到系统程序,就是装饰器模式。不断的在原有的代码基础上扩展也的业务和功能。不影响原来程序本身的属性和行为。
JavaScript装饰器呢,就是对类、类属性、类方法之类的一种装饰,可以理解为在原有代码外层又包装了一层处理逻辑。这样就可以做到不直接修改代码,就实现某些功能。
在JavaScript代码中高阶函数就可以实现装饰器的效果。通过调用一个函数来包装另外一个函数。
代码如下:
function people(name) {
console.log('Hello, iam ' + name);
}
function peopleDecorator(wrapped) {
return function () {
console.log('穿搭衣服');
const result = wrapped.apply(this, arguments);
console.log('穿搭结束');
return result;
}
}
const result = peopleDecorator(people);
result()
效果如下:
调用:people()
//Hello, iam undefined
调用:result()
//穿搭衣服
//Hello, iam undefined
//穿搭结束
类装饰器在类声明之前被声明(紧靠着类声明)。 类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。
类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。
在TypeScript代码中配置TS编译选项
{
"compilerOptions":{
"experimentaDecorators":true
}
}
代码如下:
const decoratorHat = (targetClass:any) => {
//类属性
targetClass.hat = "鸭舌帽"
//成员属性
targetClass.prototype.hotColor = "red"
}
@decoratorHat
class People {
constructor(){}
}
const people = new People()
console.log(People.hat);
console.log(people.hotColor);
不管是new一个实例出来,还是直接获取类的属性,都可以打印出对应的值。
修饰器函数的第一个参数,就是所要修饰的目标类。
还可以让装饰器接受参数,这就等于可以修改装饰器的行为了,这也叫做装饰器工厂。装饰器工厂是通过在装饰器外面再封装一层函数来实现。
const decoratorHat = (value:any) => { return (targetClass:any)=>{ console.log("-----",targetClass); //类属性 targetClass.hat = "鸭舌帽" //成员属性 targetClass.prototype.hotColor = value } } @decoratorHat("red") class People { constructor(){} } const people = new People() // @ts-ignore // console.log(People.hat); console.log(people.hotColor);
装饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。这意味着,装饰器能在编译阶段运行代码。也就是说,装饰器本质就是编译时执行的函数
类属性装饰器可以用在类的单个成员上,无论是类的属性、方法、get/set函数。该装饰器函数有3个参数:
比如在一个类中,制定的某个属性属于只读属性,无法修改值。我们可以设计一个@readonly
//不传递参数 function readonly(target: any, name: any, descriptor: any) { descriptor.writable = false return descriptor; } //传递参数 function enumerable(value: boolean) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { descriptor.enumerable = value; }; } class People { @readonly get username() { return "xiaofeifei" } @enumerable(false) get password(){ return "123" } } const people = new People() console.log("输出people.username", people.username); people.username = "xiaowang" people.password = "666"
定义类的属性的时候,使用get方法来定义,这样我们可以在readonly函数中接受三个参数
可以给函数的方法添加装饰器。
实际案列:记录函数的调用日志记录
//不传递参数 function readonly(target: any, name: any, descriptor: PropertyDescriptor) { descriptor.enumerable = false return descriptor; } //传递参数 function enumerable(value: boolean) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { descriptor.enumerable = value; }; } function log(target:any, name:any, descriptor:any) { const original = descriptor.value; if (typeof original === 'function') { descriptor.value = function (...args:any[]) { console.log(`${name} Arguments: ${args}`); try { const result = original.apply(this, args); console.log(`${name} Result: ${result}`); return result; } catch (e) { console.log(`${name} Error: ${e}`); throw e; } } } return descriptor; } class People { @readonly get username() { return "xiaofeifei" } @enumerable(false) get password() { return "123" } @log play(params1:number,params2:number){ return params1 + params2 } } const people = new People() console.log("输出people.username", people.username); // people.username = "xiaowang" // people.password = "666" console.log(people.play(100,200));
同样使用@符号给属性添加装饰器,他会返回三个参数
代码如下
const currency: ParameterDecorator = (targer: any, key: string | symbol, index: number) => { console.log(targer, key, index) } class People { get username() { return "xiaofeifei" } get password() { return "123" } play(@currency params1:number,params2:number){ return params1 + params2 } } const people = new People() people.play(100,200)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。