思维导图
基本理论
定义
- 装饰器就是一个方法或者叫函数,可以写到到类、方法、属性、参数,对象上,基于原有基础上扩展其功能。
为什么要用
-
从规范来讲,尽量少用继承,优先用对象进行扩充。
-
关键点在于切面:其由切点和增强点组成:类比于 before after.
-
为前端补充了 AOP 面向切面编程思想:
-
- 目的将业务功能和基础架构功能相分离:Log 日志举例子:
-
//不直接写log是因为不想将基础架构功能嵌入到业务代码里造成耦合。 function log(target: any, key: string, descriptor: PropertyDescriptor) { const oldValue = descriptor.value // fn1 函数 // 重新定义 fn1 函数 descriptor.value = function () { console.log(`记录日志...`) return oldValue.apply(this, arguments) } } class Foo { @log fn1() { console.log('业务功能1') } } const f = new Foo() f.fn1()
-
-
监控系统(性能,错误,行为分析)。
-
前置拦截以及后置拦截:执行原有函数前,做一些事情,执行原有函数后,还需要做一些事情
执行时机
- 编译阶段就执行了。所以说装饰器函数真正能触及到的,就只有类这个层面上的对象(类的原型对象):
-
// 不带参数的装饰器 function FirstClassDecorator1(targetClass:any ) { let targetClassObj = new targetClass(); targetClassObj.buy(); console.log("targetClass.name:", targetClass.name); } function SecondClassDecorator(targetClass: any) { let targetClassObj = new targetClass(); targetClassObj.buy(); console.log("targetClass.name:", targetClass.name); } @FirstClassDecorator1 class CustomerService { name: string = "下单" constructor() { } buy() { console.log(this.name + "购买"); } placeOrder() {//下单 console.log(this.name + "下单购买"); } }
弊端
- 函数式组件会出现函数提升的问题:高阶组件解决;
-
function doSomething(name) { console.log('Hello, ' + name); } function loggingDecorator(wrapped) { return function() { console.log('Starting'); const result = wrapped.apply(this, arguments); console.log('Finished'); return result; } } const wrapped = loggingDecorator(doSomething); - 多层装饰器会加大项目复杂度
设计原则
- 单一指责:每个装饰器只扩展一个功能。
- 以及开放封闭原则:仅仅对现有功能进行扩展,新旧逻辑解耦。
本质
- 就是函数,也是 @ 符的语法糖。
分类
- 类装饰器、属性装饰器、方法装饰器、参数装饰器,元数据装饰器
前端应用
react-redux
AOP
- 优势:非侵入式。
Angular
-
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-product-alerts',//选择器 templateUrl: './product-alerts.component.html',//模板template styleUrls: ['./product-alerts.component.css']//样式表链接 }) export class ProductAlertsComponent implements OnInit { constructor() { } ngOnInit() { } }
项目如何落地
- 为什么要用:旧有添加逻辑自定义属性 id,针对特定的组件需要改动源代码,同时对于纯自定也业务组件,难以支持打标签。
- 能够解决什么问题:首先符合开放封闭原则,形成通用解决方案,避免特定组件,差异处理。
- 初版方案:装饰器指责:能够精准在目标标签上打上 id,监控 sdk 负责埋点,上报用户信息,不再让装饰器承担过多的职责。
基本理论
定义
- 装饰器就是一个方法或者叫函数,可以写到到类、方法、属性、参数,对象上,基于原有基础上扩展其功能。
为什么要用
-
从规范来讲,尽量少用继承,优先用对象进行扩充。
-
关键点在于切面:其由切点和增强点组成:类比于 before after.
-
为前端补充了 AOP 面向切面编程思想:
-
- 目的将业务功能和基础架构功能相分离:Log 日志举例子:
-
//不直接写log是因为不想将基础架构功能嵌入到业务代码里造成耦合。 function log(target: any, key: string, descriptor: PropertyDescriptor) { const oldValue = descriptor.value // fn1 函数 // 重新定义 fn1 函数 descriptor.value = function () { console.log(`记录日志...`) return oldValue.apply(this, arguments) } } class Foo { @log fn1() { console.log('业务功能1') } } const f = new Foo() f.fn1()
-
-
监控系统(性能,错误,行为分析)。
-
前置拦截以及后置拦截:执行原有函数前,做一些事情,执行原有函数后,还需要做一些事情
执行时机
- 编译阶段就执行了。所以说装饰器函数真正能触及到的,就只有类这个层面上的对象(类的原型对象):
-
// 不带参数的装饰器 function FirstClassDecorator1(targetClass:any ) { let targetClassObj = new targetClass(); targetClassObj.buy(); console.log("targetClass.name:", targetClass.name); } function SecondClassDecorator(targetClass: any) { let targetClassObj = new targetClass(); targetClassObj.buy(); console.log("targetClass.name:", targetClass.name); } @FirstClassDecorator1 class CustomerService { name: string = "下单" constructor() { } buy() { console.log(this.name + "购买"); } placeOrder() {//下单 console.log(this.name + "下单购买"); } }
弊端
- 函数式组件会出现函数提升的问题:高阶组件解决;
-
function doSomething(name) { console.log('Hello, ' + name); } function loggingDecorator(wrapped) { return function() { console.log('Starting'); const result = wrapped.apply(this, arguments); console.log('Finished'); return result; } } const wrapped = loggingDecorator(doSomething); - 多层装饰器会加大项目复杂度
设计原则
- 单一指责:每个装饰器只扩展一个功能。
- 以及开放封闭原则:仅仅对现有功能进行扩展,新旧逻辑解耦。
本质
- 就是函数,也是 @ 符的语法糖。
分类
- 类装饰器、属性装饰器、方法装饰器、参数装饰器,元数据装饰器
前端应用
react-redux
AOP
- 优势:非侵入式。
Angular
-
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-product-alerts',//选择器 templateUrl: './product-alerts.component.html',//模板template styleUrls: ['./product-alerts.component.css']//样式表链接 }) export class ProductAlertsComponent implements OnInit { constructor() { } ngOnInit() { } }
项目如何落地
- 为什么要用:旧有添加逻辑自定义属性 id,针对特定的组件需要改动源代码,同时对于纯自定也业务组件,难以支持打标签。
- 能够解决什么问题:首先符合开放封闭原则,形成通用解决方案,避免特定组件,差异处理。
- 初版方案:装饰器指责:能够精准在目标标签上打上 id,监控 sdk 负责埋点,上报用户信息,不再让装饰器承担过多的职责。
基本理论
定义
- 装饰器就是一个方法或者叫函数,可以写到到类、方法、属性、参数,对象上,基于原有基础上扩展其功能。
为什么要用
-
从规范来讲,尽量少用继承,优先用对象进行扩充。
-
关键点在于切面:其由切点和增强点组成:类比于 before after.
-
为前端补充了 AOP 面向切面编程思想:
-
- 目的将业务功能和基础架构功能相分离:Log 日志举例子:
-
//不直接写log是因为不想将基础架构功能嵌入到业务代码里造成耦合。 function log(target: any, key: string, descriptor: PropertyDescriptor) { const oldValue = descriptor.value // fn1 函数 // 重新定义 fn1 函数 descriptor.value = function () { console.log(`记录日志...`) return oldValue.apply(this, arguments) } } class Foo { @log fn1() { console.log('业务功能1') } } const f = new Foo() f.fn1()
-
-
监控系统(性能,错误,行为分析)。
-
前置拦截以及后置拦截:执行原有函数前,做一些事情,执行原有函数后,还需要做一些事情
执行时机
- 编译阶段就执行了。所以说装饰器函数真正能触及到的,就只有类这个层面上的对象(类的原型对象):
-
// 不带参数的装饰器 function FirstClassDecorator1(targetClass:any ) { let targetClassObj = new targetClass(); targetClassObj.buy(); console.log("targetClass.name:", targetClass.name); } function SecondClassDecorator(targetClass: any) { let targetClassObj = new targetClass(); targetClassObj.buy(); console.log("targetClass.name:", targetClass.name); } @FirstClassDecorator1 class CustomerService { name: string = "下单" constructor() { } buy() { console.log(this.name + "购买"); } placeOrder() {//下单 console.log(this.name + "下单购买"); } }
弊端
- 函数式组件会出现函数提升的问题:高阶组件解决;
-
function doSomething(name) { console.log('Hello, ' + name); } function loggingDecorator(wrapped) { return function() { console.log('Starting'); const result = wrapped.apply(this, arguments); console.log('Finished'); return result; } } const wrapped = loggingDecorator(doSomething); - 多层装饰器会加大项目复杂度
设计原则
- 单一指责:每个装饰器只扩展一个功能。
- 以及开放封闭原则:仅仅对现有功能进行扩展,新旧逻辑解耦。
本质
- 就是函数,也是 @ 符的语法糖。
分类
- 类装饰器、属性装饰器、方法装饰器、参数装饰器,元数据装饰器
前端应用
react-redux
AOP
- 优势:非侵入式。
Angular
-
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-product-alerts',//选择器 templateUrl: './product-alerts.component.html',//模板template styleUrls: ['./product-alerts.component.css']//样式表链接 }) export class ProductAlertsComponent implements OnInit { constructor() { } ngOnInit() { } }
项目如何落地
- 为什么要用:旧有添加逻辑自定义属性 id,针对特定的组件需要改动源代码,同时对于纯自定也业务组件,难以支持打标签。
- 能够解决什么问题:首先符合开放封闭原则,形成通用解决方案,避免特定组件,差异处理。
- 初版方案:装饰器指责:能够精准在目标标签上打上 id,监控 sdk 负责埋点,上报用户信息,不再让装饰器承担过多的职责。