学习JavaScript设计模式之装饰者模式


Posted in Javascript onJanuary 19, 2016

有时我们不希望某个类天生就非常庞大,一次性包含许多职责。那么我们就可以使用装饰着模式。
装饰着模式可以动态地给某个对象添加一些额外的职责,从而不影响这个类中派生的其他对象。
装饰着模式将一个对象嵌入另一个对象之中,实际上相当于这个对象被另一个对象包装起来,形成一条包装链。

一、不改动原函数的情况下,给该函数添加些额外的功能

1. 保存原引用

window.onload = function() {
  console.log(1);
};

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

window.onload = function() {
  _onload();
  console.log(2);
}

问题:
(1)必须维护中间变量
(2)可能遇到this被劫持问题
在window.onload的例子中没有这个烦恼,是因为调用普通函数_onload时,this也指向window,跟调用window.onload时一样。

2. this被劫持:

var _getElementById = document.getElementById;
document.getElementById = function(id) {
  console.log(1);
  return _getElementById(id);
}

return _getElementById(id); // 报错“Uncaught TypeError: Illegal invocation”

因为_getElementById是全局函数,当调用全局函数时,this是指向window的,而document.getElementById中this预期指向document。

3. 解决this被劫持:

var _getElementById = document.getElementById;
document.getElementById = function(id) {
  console.log(1);
  return _getElementById.call(document, id);
}

二、用AOP装饰函数

/* 让新添加的函数在原函数之前执行(前置装饰)*/
Function.prototype.before = function(beforefn) {
  var _self = this;
  return function() {
    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;
  };
};
document.getElementById = document.getElementById.before(function() {
  console.log(1);
});

三、避免污染原型

var before = function(fn, beforefn) {
  return function() {
    beforefn.apply(this, arguments);
    return fn.apply(this, arguments);
  };
};

var after = function(fn, afterfn) {
  return function() {
    var ret = fn.apply(this, arguments);
    afterfn.apply(this, arguments);
    return ret;
  };
};

document.getElementById = before(document.getElementById, function(){
  console.log(1);
});

四、示例?插件式的表单验证

结合《学习JavaScript设计模式之策略模式》中的【表单验证】,运用到ajax提交数据验证,效果很棒!

修改上述before方法

var before = function(fn, beforefn) {
  return function() {
    if(beforefn.apply(this, arguments) === false) {
      // beforefn返回false,直接return,不执行后面的原函数
      return;
    }
    return fn.apply(this, arguments);
  };
};
/* 模拟数据验证*/
var validate = function() {
  if(username === "") {
    console.log("验证失败!");
    return false;
  }
  return true;
}
/* 模拟ajax提交*/
var formSubmit = function() {
  console.log("提交!!!");
}
username = 1;
formSubmit = before(formSubmit, validate); // 提交!!!
formSubmit();

username = "";
formSubmit = before(formSubmit, validate); // 验证失败!
formSubmit();

五、装饰者模式和代理模式

相同点:这两种模式都描述了怎么为对象提供一定程度上的间接引用,它们的实现部分都保留了对另外一个对象的引用,并且向那个对象发送请求。
区别:
(1)代理模式:当直接访问本地不方便或者不符合需求时,为这个本体提供一个替代者。本地定义关键功能,而代理提供或拒绝对它的访问,或者在访问本体之前走一些额外的事情。(其做的事情还是跟本体一样)
(2)装饰者模式:为对象动态加入行为。(一开始不能确定对象的全部功能,实实在在的为对象添加新的职责和行为)

希望本文所述对大家学习javascript程序设计有所帮助。

Javascript 相关文章推荐
网页中的图片的处理方法与代码
Nov 26 Javascript
25个好玩的JavaScript小游戏分享
Apr 22 Javascript
基于jquery ajax 用户无刷新登录方法详解
Apr 28 Javascript
图片img的src不变让浏览器重新加载实现方法
Mar 29 Javascript
判定是否原生方法的JS代码
Nov 12 Javascript
js字母大小写转换实现方法总结
Nov 13 Javascript
悬浮数字的实现案例
Feb 19 Javascript
JavaScript事件委托技术实例分析
Feb 06 Javascript
js检测判断日期大于多少天的方法
May 04 Javascript
JS+DIV+CSS实现仿表单下拉列表效果
Aug 18 Javascript
jquery简单插件制作(fn.extend)完整实例
May 24 Javascript
jquery radio的取值_radio的选中_radio的重置方法
Sep 20 Javascript
jQuery事件绑定用法详解(附bind和live的区别)
Jan 19 #Javascript
浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入
Jan 19 #Javascript
js实现有过渡渐变效果的图片轮播相册(兼容IE,ff)
Jan 19 #Javascript
jquery 重写 ajax提交并判断权限后 使用load方法报错解决方法
Jan 19 #Javascript
学习JavaScript设计模式之享元模式
Jan 18 #Javascript
纯JavaScript基于notie.js插件实现消息提示特效
Jan 18 #Javascript
学习JavaScript设计模式之责任链模式
Jan 18 #Javascript
You might like
PHP 面向对象程序设计(oop)学习笔记 (二) - 静态变量的属性和方法及延迟绑定
2014/06/12 PHP
php中异常处理方法小结
2015/01/09 PHP
PHP中的Session对象如何使用
2015/09/25 PHP
PHP htmlspecialchars()函数用法与实例讲解
2019/03/08 PHP
动态加载iframe
2006/06/16 Javascript
jQeury淡入淡出需要注意的问题
2010/09/08 Javascript
js实现带关闭按钮始终显示在网页最底部工具条的方法
2015/03/02 Javascript
JavaScript知识点总结(五)之Javascript中两个等于号(==)和三个等于号(===)的区别
2016/05/31 Javascript
WEB前端实现裁剪上传图片功能
2016/10/17 Javascript
jQuery 移动端拖拽(模块化开发,触摸事件,webpack)
2016/10/28 Javascript
值得分享的Bootstrap Table使用教程
2016/11/23 Javascript
原生js实现中奖信息无间隙滚动效果
2017/01/18 Javascript
JavaScript优化以及前段开发小技巧
2017/02/02 Javascript
jQuery实现表格奇偶行显示不同背景色 就这么简单
2017/03/13 Javascript
vue.js评论发布信息可插入QQ表情功能
2017/08/08 Javascript
javascript观察者模式实现自动刷新效果
2017/09/05 Javascript
Nuxt.js踩坑总结分享
2018/01/18 Javascript
BootStrap自定义popover,点击区域隐藏功能的实现
2018/01/23 Javascript
解决Vue大括号字符换行踩的坑
2020/11/09 Javascript
React中使用Vditor自定义图片详解
2020/12/25 Javascript
[01:17:12]职来职往完美电竞专场
2014/09/18 DOTA
django model去掉unique_together报错的解决方案
2016/10/18 Python
python实现各进制转换的总结大全
2017/06/18 Python
python批量复制图片到另一个文件夹
2018/09/17 Python
浅析Python __name__ 是什么
2020/07/07 Python
利用CSS3实现文字折纸效果实例代码
2018/07/10 HTML / CSS
建筑自我鉴定
2013/10/19 职场文书
高级电工工作职责
2013/11/21 职场文书
毕业生个人投资创业计划书
2014/01/04 职场文书
大学生职业生涯规划书参考模板
2014/03/05 职场文书
2014年9.18纪念日演讲稿
2014/09/14 职场文书
先进基层党组织材料
2014/12/25 职场文书
2016年幼儿园教师政治学习心得体会
2016/01/23 职场文书
2019奶茶店创业计划书范本!
2019/07/15 职场文书
创业计划书之健康营养产业
2019/10/15 职场文书
详解JS WebSocket断开原因和心跳机制
2021/05/07 Javascript