简介

装饰器是一种特殊类型的声明,他能附加到类声明方法属性或参数上可以修改类的行为;
说人话就是装饰器是一个方法,作用于类方法属性参数以便修改扩展相应功能。

es7中装饰器Decorators已经有提案了,但是尚未形成标准,在ts中已经进行了支持,但是ts装饰器也是一项实验性特性,在未来的版本中可能会发生改变。若要启用实验性的装饰器特性,你必须在命令行或tsconfig.json里启用experimentalDecorators编译器选项:

tsc --target ES5 --experimentalDecorators
	tsconfig.json:
	{
	    "compilerOptions": {
	        "target": "ES5",
	        "experimentalDecorators": true
	    }
	}

类装饰器

在不修改类的前提下,用来扩展类的属性或方法

普通装饰器

function Decorators(res:any){	//这里随便起,只是个名字
		console.log(res);//Animal(){}
		//可以看出res就是当前的类
		res.prototype.leg = '4';
		res.prototype.eat = function(){
			console.log('meat')
		}
	}
	@Decorators
	class Animal{
		constructor(){}
		say():void{console.log('alala')}
	}
	let A = new Animal();
	A.leg	//4  leg就是未修改类扩展的属性
	A.eat()	//meat 扩展的方法

以上的例子就是一个普通装饰器(不可传参)

装饰器工厂

相对于上边没有传参的普通装饰器,实际开发时用的更多的可能还是需要传入参数的;

function Decorators(res:any){	
		return function(tag:any){
			console.log(res)	//dahuang
			console.log(tag)	//Animal(){}
			tag.prototype.name= res;
		}
	} 
	@Decorators('dahuang')
	class Animal{
		constructor(){}
	}
	let A = new Animal();
	A.name;//dahuang

重载类的属性

function Decorators(res:any){
		return class extends res{
			leg:number = 4;
			say():void{
				console.log(this.leg)
			}
		}
	}
	@Decorators
	class Animal{
		leg:number;
		constructor(leg){this.leg = leg}
		say():void{console.log('alala')}
	}
	let A = new Animal(3);
	A.say()//4

属性装饰器

属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
//类装饰器
	function Decorators(res: any) {
	    return function (tag: any) {   }
	}
	//属性装饰器
	function changeLeg(res: any) {
	    return function (tag: any, att: any) {
	        console.log(tag)//Animal(){}
	        console.log(att)//leg
	        tag[att] = '8'
	    }
	}
	@Decorators('asd')  
	class Animal {
	    @changeLeg('3')
	    leg: number;
	    constructor() {}
	    say(){console.log(this.leg)}
	}
	let A = new Animal();
	A.say();//8

方法装饰器

应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。
方法装饰器需要传入下列3个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  3. 成员的属性描述符。
function change(res:any){
		return function(tag:any,method:any,desc:any){
			console.log(tag)	//Cat(){}
			console.log(method)	//say
			console.log(desc)	//编译版本小于ES5,为undefined。
			//尝试时如果init了tsconfig不生效,可能是因为指定了文件名称,从而编译器对其进行了忽略
			tag.eat = function(){console.log('meat')}//新增方法
			let oMethod = desc.value;				//修改方法
			desc.value = function(e:string){
				console.log(e)
				oMethod.call(this,e)
			}
		}
	}
	class Cat{
		@change('cat')
		say(){
			console.log('woofwoof')
		}
	}
	@change('window')function fun(){}//error此处装饰器无效
	let dahuang = new Cat();
	dahuang.eat()//meat
	dahuang.say('hello world')//hello world woofwoof

参数装饰器

参数装饰器表达式会在运行时当作函数被调用,可是使用其为类的原型增加一些元素数据,传入下列3个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  3. 参数在函数参数列表中的索引。
function dec(res:any){
		return function(tag:any,_name:any,ind:any){
			console.log(tag)	//Cat(){}
			console.log(_name)	//say
			console.log(ind)	//0
		}
	}
	class Cat{
		name:string;
		constructor(){}
		say(@dec('xxx' sth:string)){console.log(sth)}
	}
	let cat = new Cat();
	cat.say('hello world')	//hello world