类的修饰
许多面向对象的语言都有修饰起函数,用来修改类的行为
@testable
class MyTestableClass{
}
function testable(target){
target.isTestable = true
}
MyTestableClass.isTestable // true
复制代码
上面代码中,@testable就是修饰器。它修改了MyTestableClass这个类的行为,为它加上了静态属性isTestable。testable函数的参数target是MyTestableClass类本身。也就是说,修饰器是一个对类进行处理的函数。修饰器函数的第一个参数,就是所要修饰的目标类
如果觉得一个参数不够用,可以在修饰器外面再封装一层函数
function testable(isTestable){
return function(target){
target.isTestable = isTestable
}
}
@testable(true)
class MyTestableClass{}
MyTestableClass.isTestable // true
@testable(false)
class MyTestableClass{}
MyTestableClass.isTestable // false
复制代码
修饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。
如果想添加实例属性,可以通过目标类的prototype对象操作
function testable(target){
target.prototype.isTestable = true
}
@testable
class MyTestableClass{}
let obj = new MyTestableClass();
obj.isTestable // true
复制代码
方法的修饰
修饰器不仅可以修饰类,还可以修饰类的属性
class Person{
@readonly
name() {return `${this.first} ${this.last}`}
}
复制代码
修饰器readonly用来修饰 类 的name方法,修饰器readonly一共可以接受三个参数。
function readonly(target, name, descriptor){
// descriptor对象原来的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
}
readonly(Person.prototype, 'name', descriptor)
复制代码
修饰器第一个参数是类的原型对象,上例是Person.prototype,修饰器的本意是要 修饰类的实例,但是这个实例还没有生成,所以智能去修饰原型,第二个参数是所要修饰的属性名,第三个参数是该属性的描述对象。
多个修饰器的执行
function dec(id){
// 此处是按照修饰顺序执行
console.log('evaluated', id);
// 返回的函数则是按照反顺序执行。
return (target, property, descriptor) => console.log('executed', id)
}
class Example{
@dec(1)
@dec(2)
method(){}
}
// evaluated 1
// evaluated 2
// executed 2
// executed 1
复制代码
如果同一个方法有多个修饰器,会像剥洋葱一样,先从外到内进入,然后由内向外执行。
外层修饰器@dec(1)
先进入,但是内层修饰器@dec(2)
先执行。