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{}
}