用于给对象在运行期间动态的增加某个功能,职责等。相较通过继承的方式来扩充对象的功能,装饰器显得更加灵活,首先,我们可以动态给对象选定某个装饰器,而不用 hardcore 继承对象来实现某个功能点。其次:继承的方式可能会导致子类繁多,仅仅为了增加某一个单一的功能点,显得有些多余了。
所以,装饰器的作用:
- 是继承关系的一种替代
- 动态的类添加额外的功能
- 在不改变接口的前提下,增强类的性能
修饰器是一个对类进行处理的函数。用来修改类的行为。
注意,修饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。这意味着,修饰器能在编译阶段运行代码。也就是说,修饰器本质就是编译时执行的函数。
类的修饰器函数的第一个参数 target
指向类本身。
@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
上面代码中,修饰器 testable
可以接受参数,这就等于可以修改修饰器的行为。
前面的例子是为类添加一个静态属性, 如果想添加实例属性,可以通过目标类的 prototype
对象操作。
function testable(target){
target.prototype.isTestable = true;
}
@testable
class MyTestableClass {
// ...
}
let obj = new MyTestableClass();
obj.isTestable; // true
类的方法的修饰器函数的第一个参数 target
指向类的原型对象。
这是因为类中的方法,实际上是作用于实例对象上的。
class Person {
@readonly
getName() { return `${this.first} ${this.last}` }
}
function readonly(target, name, descriptor) {
// descriptor对象原来的值如下:
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// }
descriptor.writable = false;
return descriptor;
}
上面代码中,修饰器 readonly
用来修饰“类”的 getName
方法。
第一个参数是类的原型对象,第二个参数是所要修饰的属性名,本例中为 getName()
函数, 第三个参数为该属性的描述对象。
创建一个@log修饰器,可以起到输出日志的作用。
class Math {
@log
add(a, b) {
return a + b;
}
function log(target, name, descriptor) {
// 保存旧的方法add
const oldValue = descriptor.value;
descriptor.value = function() {
// 输出日志
console.log(`Calling ${name} with`, arguments);
return oldValue.apply(this, arguments);
};
// 必须返回descriptor对象
return descriptor;
}
}
let math = new Math();
math.add(1, 2);
上面代码中,@log
修饰器的作用就是在执行原始的操作之前,执行一次 console.log
,从而达到输出日志的目的。
修饰器只能用于类和类的方法,不能用于函数,因为存在函数提升。类是不会提升的,所以就没有这方面的问题。
ES6入门-修饰器
细说ES7 JavaScript Decorators
JavaScript-装饰器函数(Decorator)
[译]探秘ES2016中的Decorators【推荐】
ES7 Decorator 装饰器 | 淘宝前端团队
简单了解一下ES6的修饰器
装饰器模式&&ES7 Decorator 装饰器