修饰器(Decorator)是一个函数,用来修改类的行为。
@testable
class Person {
// ...
}
function testable(target) {
target.isTestable = true
}
console.log(Person.isTestable); // true
示例中的@testable
就是一个修饰器,修改了Person类的行为,为其添加了一个静态属性isTestable
修饰器对类的行为的改变,发生在代码编译阶段而非运行阶段。修饰器的本质其实就是编译时执行的函数
示例中修饰器的行为类似下面这样
class Person {
// ...
}
function testable(target) {
target.isTestable = true
return target
}
Person = testable(Person) || {}
console.log(Person.isTestable); // true
参数
修饰器的第一个参数表示要修饰的目标类
function testable(target) {
target.isTestable = true
}
如果还需要其他参数,可以在修饰器外面再封装一层函数
@testable(true)
class Person {
// ...
}
function testable(isTestable) {
return function(target){
target.isTestable = isTestable
}
}
console.log(Person.isTestable); // true
mixins
利用修饰器实现一个简单的mixins
function mixins (...list) {
return function(target) {
Object.assign(target.prototype, ...list)
}
}
const Age = {
sayAge() {
console.log(10)
}
}
const Name = {
sayName() {
console.log('wmui')
}
}
@mixins(Age,Name)
class Person {
// ...
}
let o = new Person();
o.sayName() // wmui
o.sayAge() // 10
通过mixins修饰器,把Age对象和Name对象的方法添加到Person类的实例上
方法修饰
修饰器还可以修饰类的方法
class Person {
@readonly
name() {
return 'wmui'
}
}
readonly修饰器函数可以接收三个参数,第一个是要修饰的目标对象,第二个是要修饰的属性名,第三个是该属性的描述对象
class Person {
@readonly
sayName() {
return 'wmui'
}
}
function readonly(target, name, descriptor) {
descriptor.writable = false;
return descriptor
}
let p = new Person()
p.sayName = 1
// Cannot assign to read only property 'sayName' of object
由于readonly修饰器设置了sayName()方法为只读的,所以强行改变该方法会报错
执行顺序
如果同一个方法有多个修饰器,会像剥洋葱一样,先从外到内进入,然后由内向外执行
function test(id) {
console.log('进入',id)
return function(target, name, descriptor) {
console.log('执行',id)
}
}
class Person {
@test(1)
@test(2)
sayName(){}
}
// 进入 1
// 进入 2
// 执行 2
// 执行 1
上面示例中,外层修饰器@test(1)
先进入,但是内层修饰器@test(2)
先执行
注意事项
修饰器只能用于类和类的方法,不能用于函数,因为存在函数提升