AOP 在 JavaScript 的实践

AOP 在 JavaScript 的实践

AOP

AOP(Aspect-Oriented Programming,面向切面编程)是对 OOP 的补充。面向对象是纵向编程,核心是抽象、封装、继承、多态;而面向切面编程则横向编程,它提供另外一种思考程序结构的途径来完善面向对象。

在 OOP 中,模块化的关键单元是类;AOP 中模块化单元是切面,切面能实现对关注点进行模块化扩展。如:在正常业务中,横向添加埋点功能、运行时错误信息收集功能、权限验证、性能分析等。

实现

Mokey Patch

所谓猴子补丁就是在程序运行的过程中动态的修改或替换一些模块、类、方法的实现。

1
2
3
Array.prototype.split = function(i) {
return [ this.slice(0, i), this.slice(i) ]
}

Higher Order Function

高阶函数接受一个或多个函数,并返回一个函数;常用到的高阶函数有:oncedebouncememoizefluent等。

1
2
3
4
5
6
function fluent(fn) {
return function(...args) {
fn.apply(this, args);
return this;
}
}

Decorator Pattern

通过 Decorator 模式,在不改变装饰对象的基础上,修改装饰对象的行为或动态地给装饰对象增加一些额外的职责。

1
2
3
4
5
let _onload= window.onload || function () {};
window.onload = () => {
_onload();
// other code
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const before = function(fn, before) {
return function() {
before.apply(this, arguments);
return fn.apply(this, arguments);
}
}

const after = function(fn, after) {
return function() {
const result = fn.apply(this, arguments);
after.apply(this, arguments);

return result;
}
}

Decorators

Decorators 与高阶组件函数在实现方式上并没有太大区别,但其实现方式更简洁、优雅。

1
2
3
4
@log
class Demo() {
doSomething(){}
}

场景

函数执行性能分析

1
2
3
4
class Demo {
@performance
doSomething() {}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function performance(target, prop, descriptor) {
const fn = descriptor.value;

if (Object.is(typeof fn, 'function')) {
const result = fn.apply(this, arguments);

performance.measure();
performance.getEntries()
.map(entry => JSON.stringify(entry))
.forEach(json => console.log(json));

return result;
}
}

表单校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const validateRules = {
expectNumber(val) {
return Reflect.apply(Object.prototype.toString, val, []);
},
maxLength(value) {
return value <= 30
}
};

function validate(value) {
return Object.keys(validateRules)
.every(key => validateRules[key](value));
}

function enableValidate(target, name, descriptor) {
const fn = descriptor.value;

if (Object.is(typeof fn, 'function')) {
descriptor.value = function (value) {
return validate(value)
? fn.apply(this, [value])
: console.error('Form validate failed!')
}
}
return descriptor
}

class Form {

@enableValidate
submit(form) {}
}

日志埋点

在某些业务操作中记录、统计用户的具体操作,如:百度埋点、谷歌统计

加密、验签

相比其他行业,支付行业往往对安全性要求比较高;在发送数据前,需要对数据进行签名、加密等操作