在软件开发过程中,经常会有一些与功能逻辑本身无关的、重复性的代码。可以通过装饰器模式进行抽象,在需要的地方直接进行使用即可
装饰器模式
-
模式定义
它是一种结构型设计模式,旨在促进代码复用,在不改变现有对象的情况下,动态地给该对象及其属性添加一些额外的职责,即扩展功能
-
模式作用
可以对代码逻辑进行合理拆分,轻松实现代码的
重用性
和低耦合性
;并且与继承相比更加灵活(即插即用) -
模式实现
既可以使用 ECMAScript 标准语法提供的装饰器,也可以使用 TypeScript 提供的装饰器
-
生活示例
在生活中经常吃的煎饼,可以在其中加鸡蛋、烤肠等,使其更加美味。但不管加啥,原先的煎饼还是那个煎饼
装饰器原理
-
无参数装饰器
function readonly(target, name, descriptor) { descriptor.writable = false return descriptor }
-
多参数装饰器
function decorationFactory(params) { // 装饰器工厂 return function(target, name, descriptor) { // 装饰器 // target 当前被装饰的对象 // name 所要装饰的属性名称 // descriptor 属性的描述对象,对应 Object.defineProperty 方法中的 descriptor } }
-
使用方式
@ + 函数名
放在被装饰对象的前面,可以装饰 类、类的属性、类的方法、属性存取器 -
实现原理
装饰器本质就是编译时执行的函数
装饰器参数详解
-
装饰器装饰类时
只有一个
target
参数表示类本身 -
装饰器装饰类的方法时
target
表示类的原型对象name
表示所要装饰的类方法名称descriptor
表示类方法的描述对象,对应Object.defineProperty
方法中的descriptor
descriptor.value
表示所要装饰的类方法本身
知识扩展
-
方法作用
Object.defineProperty()
会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象 -
基本语法
Object.defineProperty(obj, prop, descriptor)
obj
定义属性的对象prop
要定义或修改的属性名称descriptor
被定义或修改的属性描述符 -
对象中的属性描述符
enumerable
定义对象的属性是否可以在for...in
和Object.keys()
中被枚举,默认值为true
可枚举的const enumeration = { name: 'adiu', age: 28 } Object.keys(enumeration) // ['name', 'age'] Object.defineProperty(enumeration, 'age', { enumerable: false }) Object.keys(enumeration) // ['name']
value
和writable
分别定义了属性的值(数值、对象、函数等)和 是否可以对属性进行赋值更改;前者的默认值为undefined
,后者的默认值为true
可更改const enumeration = { name: 'adiu', age: 28 } Object.defineProperty(enumeration, 'age', { value: 18, writable: false }) enumeration.age // 18 enumeration.age = 12 // Uncaught TypeError: Cannot assign to read only property 'age' of object '#<Object>'
装饰器应用
-
使用装饰器上报日志信息
详情可参阅 第 34 期 - 通过 Beacon 实现日志埋点及上报 一文中的设计方案
-
使用装饰器写组件
详情可参阅 第 59 期 - 高效利器之跨技术栈组件库 一文中的组件
API
定义
装饰器语法文档
一起学习,加群交流看 沸点