装饰器(Decorator)是一种与类(class)相关的语法,用来注释或修改类和类方法。许多面向对象的语言都有这项功能。
装饰器是一种函数,写成@ + 函数名
。它可以放在类和类方法的定义前面。
装饰器可以用来装饰整个类
@testable
class MyTestableClass {
// ...
}
function testable(target) {
target.isTestable = true;
}
MyTestableClass.isTestable // true
上面代码中,@testable
就是一个装饰器。它修改了MyTestableClass
这个类的行为,为它加上了静态属性isTestable
。testable
函数的参数target
是MyTestableClass
类本身。
前面的例子是为类添加一个静态属性,如果想添加实例属性,可以通过目标类的prototype
对象操作。
function testable(target) {
target.prototype.isTestable = true;
}
@testable
class MyTestableClass {}
let obj = new MyTestableClass();
obj.isTestable // true
上面代码中,装饰器函数testable
是在目标类的prototype
对象上添加属性,因此就可以在实例上调用。
下面是另外一个例子。
// mixins.js
export function mixins(...list) {
return function (target) {
Object.assign(target.prototype, ...list)
}
}
// main.js
import { mixins } from './mixins'
const Foo = {
foo() { console.log('foo') }
};
@mixins(Foo)
class MyClass {}
let obj = new MyClass();
obj.foo() // 'foo'
上面代码通过装饰器mixins
,把Foo
对象的方法添加到了MyClass
的实例上面。可以用Object.assign()
模拟这个功能。
const Foo = {
foo() { console.log('foo') }
};
class MyClass {}
Object.assign(MyClass.prototype, Foo);
let obj = new MyClass();
obj.foo() // 'foo'
实际开发中,React 与 Redux 库结合使用时,常常需要写成下面这样。
class MyReactComponent extends React.Component {}
export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);
有了装饰器,就可以改写上面的代码。
@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}
相对来说,后一种写法看上去更容易理解。
装饰类方法:
class Boy{
@log
add(a,b){
return a+b
}
}
function log(target,name,descriptor){
//target是类本身
//name 是所要装饰的类的属性名(其实就是类的方法名)
//descriptor是该属性(方法)的描述对象
let oldValue=descriptor.value; // 先留存初始的类方法的内容
descriptor.value=function(){
//装饰这个类,给这个类新增一些要装饰的逻辑
console.log(`calling ${name} with`,arguments);
//执行原本的方法
oldValue.apply(this,arguments)
}
// 返回新的描述对象,修改类方法的值
return descriptor
}
const math =new Boy();
console.log(math.add(2,3))
//calling add with [Arguments] { '0': 2, '1': 3 }
//5