Decorator
1. 什么是装饰器
Decorator(装饰器),从名字上很容易让我们联想到装饰者模式。
简单来讲,装饰者模式就是一种在不改变原类和使用继承的情况下,动态地扩展对象功能的设计理论。
ES6 中 Decorator 功能亦如此,其本质也不是什么高大上的结构,就是一个普通的函数,用于扩展类属性和类方法。
Decorator 的两大优点:
- 装饰器是典型的AOP(面向切面)思想,能把与核心业务无关的通用逻辑抽离出来。
- 可以动态扩展对象的能力,且不影响同类的其他实例。
2. 装饰器使用
Decorator 修饰对象有两种:类和类属性 / 方法。
类的装饰
当对类本身进行装饰时,接收一个参数(类本身):
@decorator
class A {}
// 等同于
class A {}
A = decorator(A) || A;
如果想要传递参数,可以在装饰器外层再封装一层函数:
function testable(isTestable) {
return function (target) {
target.isTestable = isTestable;
};
}
@testable(true)
class MyTestableClass {}
MyTestableClass.isTestable; // true
@testable(false)
class MyClass {}
MyClass.isTestable; // false
类属性 / 方法的装饰
当对类属性或方法进行装饰时,能接收三个参数:target(类的原型)、propertyKey(属性名)、descriptor(属性描述符)。
多个装饰器
如果一个方法有多个装饰器,就像洋葱一样:先从外到内进入,再由内到外执行。
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) 先执行。
注意:装饰器不能用于修饰普通函数,因为函数存在变量声明情况,会产生歧义。
3. 使用场景
将 mixins 写成装饰器,让使用更简洁:
function mixins(...list) {
return function (target) {
Object.assign(target.prototype, ...list);
};
}
const Foo = {
foo() { console.log('foo'); }
};
@mixins(Foo)
class MyClass {}
const obj = new MyClass();
obj.foo(); // "foo"
4. core-decorators.js 常用装饰器
@autobind
autobind 装饰器使得方法中的 this 绑定到原始对象(避免回调中 this 丢失):
import { autobind } from 'core-decorators';
class Person {
@autobind
getPerson() { return this; }
}
const person = new Person();
const getPerson = person.getPerson;
getPerson() === person; // true
补充:
@readonly、@deprecate、@nonconfigurable、@enumerable等也来自core-decorators,分别用于只读、废弃提醒、不可配置等场景。需要@babel/plugin-proposal-decorators(legacy 模式)才能编译。
来源整理自:我的有道云笔记



