浅谈ES7的修饰器

·  阅读 929

类的修饰

许多面向对象的语言都有修饰起函数,用来修改类的行为

@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)先执行。

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改