一、概念
- 允许在不改变原有对象的基础上,通过将对象包装在一个装饰器对象中来动态地添加额外的功能或责任;
- 简单地说: 允许向一个现有的对象添加新的功能,同时又不改变其结构
- 装饰器和目标是分离和解耦的
二、演示
- 以下示例中,定义了一个装饰器函数 decorator,接受一个函数作为参数,并返回一个新的函数;
- 该新函数就是 HOC 高阶函数,在调用原始函数之前可以做一些其他事情,常用于实现日志记录、性能追踪、缓存等功能的封装,以及在框架和库中为现有类添加新的功能
function decorator(originalFunc) {
return function () {
return originalFunc.apply(this, arguments)
}
}
function sayHello(name) {
console.log('Hello,', name)
}
var decoratedSayHello = decorator(sayHello)
decoratedSayHello('zhangsan')
- Decorator 相当于一个装饰,有自己的属性和方法,同时可以也执行目标上的方法;
class Circle {
draw() {
console.log('画一个圆')
}
}
class Decorator {
constructor(circle) {
this.circle = circle
}
draw() {
this.circle.draw()
console.log('画一个边')
}
}
const decorator = new Decorator(new Circle())
decorator.draw()
- TS : tsconfig 需要设置支持装饰器模式
"experimentalDecorators": true
- @为装饰器特定标识
function decorato(val: boolean) {
return function (target: any) {
target.isTestable = val
}
}
@decorato(false)
class DecoratorFoo {
static isTestable?: boolean
}
console.log(DecoratorFoo.isTestable)
Foo
中的方法 getName
的属性描述符 writable
通过装饰器函数 readOnly
修改为 fasle
;
function readOnly(val: boolean) {
return function (target: any, key: string, descriptor: PropertyDescriptor) {
descriptor.writable = val
}
}
class Foo {
@readOnly(false)
sayHi() {}
}
const f = new Foo()
console.log(Object.getOwnPropertyDescriptor(f.__proto__, 'sayHi'))
import { connect } from 'react-redux'
export default TodoList = connect(mapStateToProps, mapDispatchToProps)(TodoList)
@connect(mapStateToProps, mapDispatchToProps)
export default TodoList extends React.Component { }
AOP
- 面向切面编程,使得页面和系统基础功能分离,如 redux-thunk
function log(target: any, key: string, descriptor: PropertyDescriptor) {
console.log(target)
console.log(key)
console.log(descriptor)
const oldValue = descriptor.value
descriptor.value = function () {
console.log(`记录日志 ...`)
return oldValue.apply(this, arguments)
}
}
class Foo {
@log
business() {
console.log('业务')
}
}
const f = new Foo()
f.business()