资讯专栏INFORMATION COLUMN

JavaScript装饰者模式

Taste / 1701人阅读

摘要:用户名不能为空密码不能为空校验未通过使用优化代码返回的情况直接,不再执行后面的原函数用户名不能为空密码不能为空

本文是《JavaScript设计模式与开发实践》的学习笔记,例子来源于书中,对于设计模式的看法,推荐看看本书作者的建议。

什么是装饰者模式?

给对象动态增加职责的方式成为装饰者模式。

装饰者模式能够在不改变对象自身的基础上,在运行程序期间给对象动态地添加职责。这是一种轻便灵活的做法,装饰者是一种“即付即用”的方式,比如天冷了就多穿一件外套。

装饰函数

想要为函数添加一些功能,最简单粗暴的方式就是直接改写该函数,但是这是最差的办法,直接违反了开放——封闭原则。

var a = function(){
    alert(1)
}
// 改成
var a = function(){
    alert(1)
    alert(2)
}

很多时候我们不想碰原函数,也许原函数是其他同事编写的,甚至在一个古老的项目中,这个函数的源代码被隐藏在一个我们不愿触碰的阴暗角落里。现在需要不改变源代码的情况下,给函数增加功能。

我们通过保存原引用的方式改写某个函数。

var a = function(){
    alert(1)
}
var _a = a
a = function(){
    _a()
    alert(2)
}
a()

这是实际开发中很常见的一个做法,比如我们想给 window 绑定 onload 事件,但是又不确定这个事件是不是已经被其他人绑定过,为了避免覆盖掉之前的 window.onload 函数中的行为,先保存 window.onload,把它放入新的 window.onload。

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

var _onload = window.onload || function(){}

window.onload = funtion(){
    _onload()
    alert(2)
}

这样的代码是符合封闭——开放原则,我们在增加新功能的时候确实没有修改原来的代码,但是这种方式存在两个问题:

必须维护 _onload 这个中间变量,虽然看起来不起眼,但是如果函数装饰链较长,或者需要装饰的函数变多,这些中间变量的数量也会越来越多。

其实还遇到了 this 被劫持的问题,在 window.onload 的例子中没有这个烦恼,因为调用 _onload 的时候 this 也指向 window,跟调用 window.onload 的时候一样。

用 AOP 装饰函数

AOP(Aspect Oriented Programming)面向切面编程的主要作用是:把一些跟核心业务逻辑无关的功能抽离出来,这些跟业务逻辑无关的功能通常包括日志统计、安全控制、异常处理等。把这些功能抽离出来以后,再通过“动态织入”的方式掺入业务逻辑模块中。这样的好处首先是可以保持业务逻辑模块的纯净和高内聚性,其次是可以很方便地复用日志统计等功能模块。

首先给出 Function.prototype.before 和 Function.prototype.after 方法:

Function.prototype.before = function(beforefn){
    // 保存原函数的引用
    var _self = this
    // 返回包含原函数和新函数的“代理函数”
    return function(){
        // 执行新函数,保证this不被劫持,
        // 新函数接受的参数也会被原封不动地传入原函数,
        // 新函数在原函数之前执行
        beforefn.apply(this,arguments)
        return _self.apply(this.arguments)
    }
}

Function.prototype.after = function(afterfn){
    var _self = this
    return function(){
        var ret = _self.apply(this,arguments)
        afterfn.apply(this,arguments)
        return ret
    }
}

“代理函数”只是结构上像代理而已,并不承担代理的职责(比如控制对象的访问),它的工作是把请求分别转发给新添加的函数和原函数,且负责保证它们的执行顺序。

再回到 window.onload 的例子中,用 Function.prototype.after 来增加新事件:

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

window.onload = (window.onload || function(){}).after(function(){
    alert(2)
}).after(function(){
    alert(3)
})
AOP 的应用实例

(1)数据统计上报


    
    

showLogin 函数既要负责打开浮层,又要负责数据上报,两个功能耦合在一个函数里,使用 AOP 分离:




(2) 插件式表单验证



    用户名:
    密码: 
    


formatSubmit 函数承担了两个职责,除了提交ajax请求,还要验证用户输入的合法性。我们把校验输入的逻辑放到validata函数中,并约定当validata函数返回false的时候表示校验未通过。

var validata = function(){
    if ( username.value === "" ){
        alert ( "用户名不能为空" );
        return false;
    }
    if ( password.value === "" ){
        alert ( "密码不能为空" );
        return false;
    }
}

var formSubmit = function(){
    if ( validata() === false ){ // 校验未通过
    return;
    }
    var param = {
        username: username.value,
        password: password.value
    }
    ajax( "http:// xxx.com/login", param );
}

submitBtn.onclick = function(){
    formSubmit();
}

使用AOP优化代码

Function.prototype.before = function( beforefn ){
    var __self = this;
    return function(){
    if ( beforefn.apply( this, arguments ) === false ){
    // beforefn 返回false 的情况直接return,不再执行后面的原函数
        return;
    }
    return __self.apply( this, arguments );
    }
}

var validata = function(){
    if ( username.value === "" ){
        alert ( "用户名不能为空" );
        return false;
    }
    if ( password.value === "" ){
        alert ( "密码不能为空" );
        return false;
    }
}
var formSubmit = function(){
    var param = {
        username: username.value,
        password: password.value
    }
    ajax( "http:// xxx.com/login", param );
}

formSubmit = formSubmit.before( validata );
    submitBtn.onclick = function(){
        formSubmit();
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108950.html

相关文章

  • JavaScript设计模式----装饰模式

    摘要:声明这个系列为阅读设计模式与开发实践曾探著一书的读书笔记装饰者模式的定义装饰者模式能够在不改变对象自身的基础上,在程序运行期间给对像动态的添加职责。与继承相比,装饰者是一种更轻便灵活的做法。装饰者模式的作用就是为对象动态的加入某些行为。 声明:这个系列为阅读《JavaScript设计模式与开发实践》 ----曾探@著一书的读书笔记 装饰者模式的定义: 装饰者(decorator)模式能...

    rose 评论0 收藏0
  • 5 分钟即可掌握的 JavaScript 装饰模式与 AOP

    摘要:下装饰者的实现了解了装饰者模式和的概念之后,我们写一段能够兼容的代码来实现装饰者模式原函数拍照片定义函数装饰函数加滤镜用装饰函数装饰原函数这样我们就实现了抽离拍照与滤镜逻辑,如果以后需要自动上传功能,也可以通过函数来添加。 showImg(https://segmentfault.com/img/bVbueyz?w=852&h=356); 什么是装饰者模式 当我们拍了一张照片准备发朋友...

    chunquedong 评论0 收藏0
  • javascript设计模式 --- 装饰模式

    摘要:设计模式装饰者模式何为装饰者,意思就是,在不影响对象主功能的情况下,再添加一些额外的功能,使对象具备更多的功能。与继承相比,装饰者是一种更灵活轻便的做法。 javascript设计模式 --- 装饰者模式 何为装饰者,意思就是,在不影响对象主功能的情况下,再添加一些额外的功能,使对象具备更多的功能。与继承相比,装饰者是一种更灵活轻便的做法。下面我们看看javascript里装饰者模式 ...

    kumfo 评论0 收藏0
  • javascript设计模式--装饰模式

    摘要:装饰者模式定义装饰者模式能够在不改变对象自身的基础上,在程序运行期间给对像动态的添加职责。与继承相比,装饰者是一种更轻便灵活的做法。 装饰者模式 定义 : 装饰者(decorator)模式能够在不改变对象自身的基础上,在程序运行期间给对像动态的添加职责。与继承相比,装饰者是一种更轻便灵活的做法。 在不改变对象自身的基础上,在程序运行期间给对象动态地添加一些额外职责 特点 : 可以动态的...

    haoguo 评论0 收藏0
  • JavaScript设计模式七:装饰模式

    摘要:装饰者模式装饰者模式提供比继承更有弹性的替代方案。装饰者用于包装同接口的对象,用于通过重载方法的形式添加新功能,该模式可以在被装饰者的前面或后面加上自己的行为以达到特定的目的。简单的理解给对象动态添加职责的方式称为装饰着模式。 装饰者模式 装饰者模式提供比继承更有弹性的替代方案。装饰者用于包装同接口的对象,用于通过重载方法的形式添加新功能,该模式可以在被装饰者的前面或后面加上自己的行为...

    alexnevsky 评论0 收藏0
  • JavaScript 模式》知识点小抄本(上)

    摘要:单体模式有以下优点用来划分命名空间,减少全局变量数量。通常我们使用操作符创建单体模式的三种选择,让构造函数总返回最初的对象使用全局对象来存储该实例不推荐,容易全局污染。实现该工厂模式并不困难,主要是要找到能够穿件所需类型对象的构造函数。 介绍 最近开始给自己每周订个学习任务,学习结果反馈为一篇文章的输出,做好学习记录。 这一周(02.25-03.03)我定的目标是《JavaScri...

    didikee 评论0 收藏0

发表评论

0条评论

Taste

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<