一般在JavaScript中为了让部分代码延迟执行,一想起的自然是 setTimeout,比如:

setTimeout(() => {
  // doing
}, 0);

这种代码或许你不知道写过多少遍,但,我们在 setTimeout 中多数情况下会去调用另一个方法:

setTimeout(() => {
  this.fn();
}, 0);

你会发现,我们一直都在重复写着 setTimeout,再套用一个匿名函数,最后才真正去编写我们需要执行的方法。我越来越讨厌这种写法,老是写着一些无关系要多余的代码。

使用Angular的同学对 @Component 不陌生,里面大量的使用这种ES7才会有的“修饰器”。

修饰器是一个函数,用于修改类行为。

那, 应该怎么编写一个更干净的 setTimeout,比如,我希望这样来编写我的timeout:

@timeout(1000)
fn() {
  // doing
}

this.fn();

对应的 timeout 修饰器代码:

// timeout.ts
export function timeout(milliseconds: number = 0) {
  return function(target, key, descriptor) {
    // value 值相当于上面示例中 `change` 方法。
    var orgMethod = descriptor.value;
    descriptor.value = function(...args) {
      setTimeout(() => {
        orgMethod.apply(this, args);
      }, milliseconds);
    };
    return descriptor;
  }
}

target:实例对象,即 IndexComponent 实例化对象。
key:方法名称,即 fn
descriptor:对象描述,同Object.getOwnPropertyDescriptor() 。

怎么样,这样子写的代码是不是更酷?

修饰器目前只能在ES7才会有,但一些在Typescript、Babel等转码器已经被支持,特别是Angular2应用中更是给予非常重要的地位。而且应用范围可以非常广,比如类、类方法和属性。

结论

以上只是一个很简单的修饰器示例,你可以根据需要生产一些有意思的修饰器,让编写的代码更优雅、更干净。完整示例