先解决一个问题:想要为函数加一个功能该怎么办,比如
const func = function() {
console.log(1);
}
我们想添加一个功能打印2
解决方法1:简单粗暴,直接改写原函数
const func = function() {
console.log(1)
console.log(2);
}
此方法的确可以解决问题,但是若想添加的方法很复杂呢?此时我们得添加很冗杂的代码到原函数,且此方法严重违背开放-封闭原则(封装变化、降低耦合),所以pass
解决办法2:通过保存原引用的方式来可以改写某个函数
let func = function() {
console.log(1);
}
let _func = func
func = function() {
_func();
console.log(2);
}
func(); // 依次输出1、2
此方法也可以解决问题,比第一种好得多。但仍有一些问题
this引用被劫持了
我们得维护_a这个中间变量,当项目变复杂,这个问题也很难解决
解决办法3:用AOP(面向切向编程)装饰函数
Function.prototype.before = function(beforefn) {
const self = this; // 保存原函数的引用
return function() {
beforefn.apply(this, arguments); // 先执行新函数,修正this
return self.apply(this, arguments); // 再执行原函数
}
}
Function.prototype.after = function(afterfn) {
const self = this;
return function() {
const ret = self.apply(this, arguments); // 先执行原函数
afterfn.apply(this, arguments); // 再执行新函数
return ret;
}
}
const func = function() {
console.log(1);
}
func = func.before(function() {
console.log(0);
}).after(function() {
console.log(2);
});
func(); // 依次输出0,1,2
此时不仅满足了在1后面添加了打印2,还在1前面打印了0,并且基本没有副作用,唯一的缺点就是代码有点冗长。
高阶函数
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);
es7装饰符
装饰者模式听着和装饰符挺像的,其实装饰符也是装饰者模式的一种模式,以上的方法都是为了修饰函数,而当我们不想修改类的代码,但是想给类添加一些功能就用到了装饰符。具体使用请学习ECMAScript 6 入门
总结:当我们想给某个函数或者类添加新的功能而又不想去更改原函数或者原类的时候,利用装饰者模式可以很好地帮助我们解决问题