许多面向对象的语言都有修饰起函数,用来修改类的行为函数
@testable
class MyTestableClass{
}
function testable(target){
target.isTestable = true
}
MyTestableClass.isTestable // true
复制代码
上面代码中,@testable就是修饰器。它修改了MyTestableClass这个类的行为,为它加上了静态属性isTestable。testable函数的参数target是MyTestableClass类自己。也就是说,修饰器是一个对类进行处理的函数。修饰器函数的第一个参数,就是所要修饰的目标类ui
若是以为一个参数不够用,能够在修饰器外面再封装一层函数this
function testable(isTestable){
return function(target){
target.isTestable = isTestable
}
}
@testable(true)
class MyTestableClass{}
MyTestableClass.isTestable // true
@testable(false)
class MyTestableClass{}
MyTestableClass.isTestable // false
复制代码
修饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。lua
若是想添加实例属性,能够经过目标类的prototype对象操做spa
function testable(target){
target.prototype.isTestable = true
}
@testable
class MyTestableClass{}
let obj = new MyTestableClass();
obj.isTestable // true
复制代码
修饰器不只能够修饰类,还能够修饰类的属性prototype
class Person{
@readonly
name() {return `${this.first} ${this.last}`}
}
复制代码
修饰器readonly用来修饰 类 的name方法,修饰器readonly一共能够接受三个参数。code
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
复制代码
若是同一个方法有多个修饰器,会像剥洋葱同样,先从外到内进入,而后由内向外执行。ip
外层修饰器@dec(1)
先进入,可是内层修饰器@dec(2)
先执行。ci