da宗熊

当前位置: 首页 / 博客

es6修饰器-decorator

06-30,2016 / da宗熊

Tags: 前端

初识

修饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。
这意味着,修饰器能在编译阶段运行代码。

function testable(target){
  target.isTestable = true;
}

@testable
class Test {

}
console.log(Test.isTestable); // true

上述代码,等同于:

Test = testable(Test);

参数

修饰器的第1个参数,指向被修饰的类。
如果觉得1个参数不够用,可以在修饰器外面再封装一层函数:

function testable(isTestable) {
  return function(target) {
    target.isTestable = isTestable;
  };
}

@testable(true)
class Test2 {}
console.log(Test2.isTestable); // true

例子中,是添加了一个静态属性,如果想给类的实例添加属性,则可通过目标类的 prototype 属性:

function testable(isTestable) {
  return function(target) {
    target.prototype.isTestable = isTestable;
  }
}

看下面另一个例子。

function mixins(...list) {
  return function(target) {
    Object.assign(target.prototype, ...list);
  };
}

const Foo = {
  say() {
    console.log('hello');
  }
};

@mixins(Foo)
class MyClass {}

const myClass = new MyClass();
myClass.say(); // 'hello'

通过 mixins 修饰符,把Foo的属性,添加到了 MyClass 的实例。


方法的修饰

修饰符不仅可以修饰类,同时也可以修饰类的方法

function readonly(target, attrName, descriptor) {
  // 让当前属性 or 方法,不可被重写
  descriptor.writable = false;
}

class Test {
  @readonly
  name() {
    console.log('big bear');
  }
};

const test = new Test();
test.name = 'small bear'; // throw error

上述代码,将属性 name 设置为只读。
readyonly 修饰器,有3个参数,target 是修饰的类,attrName 是修饰的方法名,descriptor 是属性的描述对象。

descriptor 包含的值如下:

  descriptor = {
    value: '该属性对应的函数',
    enumerable: 是否可枚举,就是for/in时,出现否,默认false
    configurable: 是否可以继续配置,是否可删除,默认 true,如果是 false,则属性不能再被配置和删除了
    writable: 是否可写入,默认 true
  };

看下面复杂的例子:

function send(url) {
  return function(target, attr, descriptor) {
    const fn = descriptor.value;
    // 重新定义当前的函数
    descriptor.value = function(...args) {
      const params = fn.call(this, ...args);
      return new Promise((resolve, reject) => {
        setTimeout(() => resolve({url, params}), 1000);
      });
    };
  };
}

class MyClass {
  @send('/post')
  submit() {
    return {
      author: '宗熊',
      content: '内容',
    };
  }
}

const myClass = new MyClass();
myClass.submit().then(data => console.log(data)); // 1 秒后,输出: {"url":"/post","params":{"author":"宗熊","content":"内容"}}

注意

1、因为函数的定义,存在提升,所以 decorator 不能用在函数上

function testable(target) {
  target.isTestable = true;
}

@testable
function A() {}
console.log(A.isTestable);  // undfined or throw error

2、也不要用于非类的地方
3、在线测试

@2022 da宗熊
Email: 1071093121@qq.com