我们继续来看一下,类方法装饰器,类属性装饰器和类访问器装饰器。
类方法装饰器
装饰器可以装饰类的方法,它会修改类的方法。
class C {
@trace
toString() {
return 'C';
}
}
// 相当于
C.prototype.toString = trace(C.prototype.toString);
方法装饰器会返回一个新的函数,取代原来的方法,也可以不返回值,表示依然使用原来的方法。如果返回其他类型的值,就会报错。也就是说,如果返回值的话,必须返回一个函数。
class Person {
constructor(name){
this.name = name;
}
@MyName
getName(){
console.log(this.name);
return this.name;
}
}
function MyName(target, key, descriptor){
// console.log(target, key, descriptor);
const fn = descriptor.value;
descriptor.value = function(...args){
console.log(`${key} is called...` );
// fn && fn(...args);
fn && fn.apply(this, args);
}
}
let person = new Person('Tom');
person.getName();
参数说明:
- target: 类的原型对象,上例是Person.prototype;
- key: 所要修饰的属性名 name;
- descriptor: 该属性的描述对象;
装饰器第一个参数是类的原型对象,上例是Person.prototype,装饰器的本意是要“装饰”类的实例,但是这个时候实例还没生成,所以只能去装饰原型(这不同于类的装饰,那种情况时target参数指的是类本身);第二个参数是所要装饰的属性名,第三个参数是该属性的描述对象。
类的属性
属性装饰器的类型描述如下。 装饰器可以装饰类属性。(新语法)
type ClassFieldDecorator = (value: undefined, context: {
kind: "field";
name: string | symbol;
access: { get(): unknown, set(value: unknown): void };
static: boolean;
private: boolean;
}) => (initialValue: unknown) => unknown | void;
function logged(value, { kind, name }) {
if (kind === "field") {
return function (initialValue) {
console.log(`initializing ${name} with value ${initialValue}`);
return initialValue;
};
}
// ...
}
class C {
@logged x = 1;
}
new C();
// initializing x with value 1
用户可以选择让装饰器返回一个初始化函数,当该属性被赋值时,这个初始化函数会自动运行,它会收到属性的初始值,然后返回一个新的初始值。属性装饰器也可以不返回任何值。
如果不使用装饰器语法,则如下所写。
let initializeX = logged(undefined, {
kind: "field",
name: "x",
static: false,
private: false,
}) ?? (initialValue) => initialValue;
class C {
x = initializeX.call(this, 1);
}
访问器
类装饰器引入了一个新命令accessor,用来属性的前缀。(新语法)
class C {
accessor x = 1;
}
它是一种简写形式,相当于声明属性 x
是私有属性 #x
的存取接口。上面的代码等同于下面的代码。
class C {
#x = 1;
get x() {
return this.#x;
}
set x(val) {
this.#x = val;
}
}
accessor 命令前面还可以接受属性装饰器,这里不在举例了。
好了,下次介绍多装饰器的情况。