ES6功能扩展-装饰器

修饰器(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)先执行

注意事项

修饰器只能用于类和类的方法,不能用于函数,因为存在函数提升

posted @ 2021-09-29 12:59  wmui  阅读(135)  评论(0编辑  收藏  举报