TS-装饰器

1.装饰器

(1)什么是装饰器

  • Decorator 是 ES7 的一个新语法,目前仍处于提案中,
  • 装饰器是一种特殊类型的声明,它能够被附加到类,方法, 访问器,属性或参数上
  • 被添加到不同地方的装饰器有不同的名称和特点
    • 附加到类上, 类装饰器
    • 附加到方法上,方法装饰器
    • 附加到访问器上,访问器装饰器
    • 附加到属性上,属性装饰器
    • 附加到参数上,参数装饰器

(2)装饰器基本格式

普通装饰器:给Person这个类绑定了一个普通的装饰器test,这个装饰器的代码会在定义类之前执行, 并且在执行的时候会把这个类传递给装饰器。

	function test(target) {
	    console.log('test');
	}
	@test
	class Person {}

装饰器工厂:给Person这个类绑定了一个装饰器工厂,在绑定的时候由于在函数后面写上了(), 所以会先执行装饰器工厂拿到真正的装饰器,真正的装饰器会在定义类之前执行, 所以紧接着又执行了里面。

	function demo() {  //装饰器工厂
	    console.log('demo out');
	    return (target)=>{  //装饰器
	        console.log('demo in');
	    }
	}
	@demo()
	class Person {}

装饰器组合:普通的装饰器可以和装饰器工厂结合起来一起使用,结合起来一起使用的时候, 会先从上至下的执行所有的装饰器工厂, 拿到所有真正的装饰器,然后再从下至上的执行所有的装饰器。
执行顺序:demo out / def out / abc / def in / demo in / test

	function test(target) {
	    console.log('test');
	}
	function demo() {  //装饰器工厂
	    console.log('demo out');
	    return (target)=>{  //装饰器
	        console.log('demo in');
	    }
	}
	function abc(target) {
	    console.log('abc');
	}
	function def() {
	    console.log('def out');
	    return (target)=>{
	        console.log('def in');
	    }
	}
	@test
	@demo()
	@def()
	@abc
	class Person {}

(3)如何在TS中使用装饰器?
在TS中装饰器也是一项实验性的特性, 所以要使用装饰器需要手动打开相关配置,修改配置文件 experimentalDecorators。

2.类装饰器

类装饰器在类声明之前绑定(紧靠着类声明)。
类装饰器可以用来监视,修改或替换类定义。
在执行类装饰器函数的时候, 会把绑定的类作为其唯一的参数传递给装饰器。
如果类装饰器返回一个新的类,它会新的类来替换原有类的定义。
类装饰器和装饰器工厂区别:类装饰器可以传递自定义参数。

	function test<T extends {new (...args:any[]):{}}>(target:T) {
	    return class extends target {
	        name:string = 'lnj';
	        age:number = 18;
	    }
	}
	@test
	class Person {}
	let p = new Person();
	console.log(p);

3.defineProperty

Object.defineProperty():可以直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
定义一个新的属性:

	let obj = {age:18};
	Object.defineProperty(obj, 'name', {
	    value:'lnj'
	});
	console.log(obj);

修改原有属性:

	let obj = {age:18};
	Object.defineProperty(obj, 'age', {
	    value:34
	});
	console.log(obj);

修改属性配置-读写:

	let obj = {age:18};
	Object.defineProperty(obj, 'age', {
	    writable:false
	})
	obj.age = 34;
	console.log(obj.age);

修改属性配置-迭代:

	let obj = {age:18, name:'lnj'};
	Object.defineProperty(obj, 'name', {
	    enumerable: false
	})
	for(let key in obj){
	    console.log(key);
	}

修改属性配置-配置:

	let obj = {age:18, name:'lnj'};
	Object.defineProperty(obj, 'name', {
	    enumerable:false,
	    configurable: false
	});
	Object.defineProperty(obj, 'name', {
	    enumerable:true,
	    configurable: false
	});
	for(let key in obj){
	    console.log(key);
	}

4.方法装饰器

  • 方法装饰器写在在一个方法的声明之前(紧靠着方法声明)。
  • 方法装饰器可以用来监视,修改或者替换方法定义。
  • 方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
    • 对于静态方法而言就是当前的类, 对于实力方法而言就是当前的实例
    • 被绑定方法的名字。
  • 被绑定方法的属性描述符。
	function test(target: any, propertyKey: string, 
	descriptor: PropertyDescriptor) {
	    descriptor.value = ():void=>{
	        console.log('my name is it666');
	    };
	}
	class Person {
	    @test
	    sayName():void{
	        console.log('my name is lnj');
	    }
	}
	let p = new Person();
	p.sayName();

5.访问器装饰器

访问器装饰器声明在一个访问器的声明之前(紧靠着访问器声明)。
访问器装饰器应用于访问器的属性描述符并且可以用来监视,修改或替换一个访问器的定义。

  • 访问器装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
    • 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
    • 成员的名字。
    • 成员的属性描述符。
  • 注意: 
    TypeScript不允许同时装饰一个成员的get和set访问器。
    取而代之的是,一个成员的所有装饰的必须应用在文档顺序的第一个访问器上
	function test(target: any, propertyKey: string,
	 descriptor: PropertyDescriptor) {
	    // console.log(target);
	    // console.log(propertyKey);
	    // console.log(descriptor);
	    descriptor.set = (value:string)=>{
	        target.myName = value;
	    }
	    descriptor.get = ():string=>{
	        return target.myName;
	    }
	}
	class Person {
	    private _name:string; // lnj
	    constructor(name:string){
	        this._name = name;
	    }
	    @test
	    get name():string{
	        return this._name;
	    }
	    set name(value:string){
	        this._name = value;
	    }
	    
	}
	let p = new Person('lnj');
	p.name = 'zs';
	console.log(p.name);
	console.log(p);

6.属性装饰器

属性装饰器写在一个属性声明之前(紧靠着属性声明)

  • 属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
    • 对于静态属性来说就是当前的类, 对于实例属性来说就是当前实例
  • 成员的名字
	function test(target:any, proptyName:string) {
	    console.log(target);
	    console.log(proptyName);
	    target[proptyName] = 'lnj';
	}
	class Person {
	    // @test
	    static age:number;
	    @test
	    name?:string;
	}
	let p = new Person();
	console.log(p);

7.参数装饰器

  • 参数装饰器写在一个参数声明之前(紧靠着参数声明)。
  • 参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
    • 对于静态成员来说是当前的类,对于实例成员是当前实例。
    • 参数所在的方法名称。
    • 参数在参数列表中的索引。
	function test(target:any, proptyName:string, index:number) {
	    console.log(target);
	    console.log(proptyName);
	    console.log(index);
	}
	class Person {
	    say(age:number,@test name:string):void{}
	}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值