在不更改原有函数逻辑的基础上新增逻辑——装饰者模式

这是我参与更文挑战的第14天,活动详情查看:更文挑战

装饰者模式常见用法

装饰者模式也可以叫做包装器(wrapper)。

场景:我们需要去更改一个很复杂的函数,给这个函数添加一些额外的功能。但是这个函数中包含了很多复杂逻辑。一般情况下,我们最好是不去动内部函数的逻辑。

在函数外部去进行更改和编写。我们可以通过保存原引用的方式来改写这个函数:

let a = function() {
    alert(1);
}

let _a = a;

a = function() {
    _a();
    alert(2);
}

a();
复制代码

这是实际开发中很常见的一种做法,比如我们想给window绑定onload事件,但是不知道之前有没有绑定过。所以我们需要在原有的onload上新增。我们在很多app生命周期中都会用到。

window.onload = function() {
    alert(1);
}

let _onload = window.onload || function() {};

window.onload = function() {
    _onload();
    alert(2);
}
复制代码

用AOP装饰函数

实际上,这种方式也会改变this的指向,如果想不改变this指向,我们在调用原有的函数时需要绑定this。
如果要实现通用这种装饰器,我们可以引入AOP来实现,并绑定this指向。

// 在原函数之前执行
Function.prototype.before = function(beforeFn) {
    let _self = this; // 保存原函数引用
    return function() {
        beforeFn.apply(this, arguments);  // 执行新函数,绑定this
        return _self.apply(this, arguments); // 执行原函数,并返回原函数执行结果
    }
}

// 在原函数之后执行
Function.prototype.after = function(afterFn) {
    let _self = this;
    return function() {
        let func = _self.apply(this, arguments);
        afterFn.apply(this, arguments);
        return func;
    }
}
复制代码

这样封装过后来看一下,我们该怎么使用。还是之前的例子:

window.onload = function() {
    alert(2);
}

// 原函数之前
window.onload = (window.onload || function() {}).before(function() {
    alert(1);
});

// 原函数之后
window.onload = (window.onload || function() {}).after(function() {
    alert(3);
    alert(4);
});
复制代码

利用装饰者模式也可以改造我们的表单提交方式,让其看起来更简洁,函数功能也可以保持相对干净。

// 在原函数之前执行
Function.prototype.before = function(beforeFn) {
    let _self = this; // 保存原函数引用
    return function() {
        if(beforeFn.apply(this, arguments) === false) { // 根据validataFunc返回的校验结果,执行函数
            return;
        }
        return _self.apply(this, arguments); // 执行原函数,并返回原函数执行结果
    }
}

const validataFunc = function() {
    if(name.value === '') {
        alert('用户名不能为空');
        return false;
    }
    if(pwd.value === '') {
        alert('密码不能为空');
        return false;
    }
}

const submitForm = function() {
    const {
        name: name.value,
        pwd: pwd.value
    }
    ajax(opts, (data) => {
        console.log('success')
    }, (err) => {
        console.log('err')
    });
}

submitForm.before(validataFunc());
复制代码

这样修改之后,校验函数和提交表单数据的函数都变得纯净起来,迁移时也更加方便,不会互相影响。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享