学习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 相关文章推荐
新浪刚打开页面出来的全屏广告代码
Apr 02 Javascript
js 页面刷新location.reload和location.replace的区别小结
Dec 24 Javascript
jQuery学习笔记之Helloworld
Dec 22 Javascript
JS添加删除一组文本框并对输入信息加以验证判断其正确性
Apr 11 Javascript
node.js中的fs.open方法使用说明
Dec 17 Javascript
js实现编辑div节点名称的方法
Dec 17 Javascript
JavaScript使用Math.Min返回两个数中较小数的方法
Apr 06 Javascript
Jquery循环截取字符串的方法(多出的字符串处理成"...")
Nov 28 Javascript
JavaScript中Require调用js的实例分享
Oct 27 Javascript
vue 挂载路由到头部导航的方法
Nov 13 Javascript
mac上配置Android环境变量的方法
Jul 08 Javascript
微信小程序 高德地图路线规划实现过程详解
Aug 05 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设计模式 Decorator(装饰模式)
2011/06/26 PHP
curl实现站外采集的方法和技巧
2014/01/31 PHP
PHP基于MySQL数据库实现对象持久层的方法
2015/06/17 PHP
详解WordPress中用于合成数组的wp_parse_args()函数
2015/12/18 PHP
js实现DIV的一些简单控制
2007/06/04 Javascript
JavaScript动态调整TextArea高度的代码
2010/12/28 Javascript
有关javascript的性能优化 (repaint和reflow)
2013/04/12 Javascript
js实现图片轮换效果代码
2013/04/16 Javascript
jquery使用ajax实现微信自动回复插件
2014/04/28 Javascript
jQuery根据用户电脑是mac还是pc加载对应样式的方法
2015/06/26 Javascript
AngularJS实现分页显示数据库信息
2016/07/01 Javascript
如何用js实现鼠标向上滚动时浮动导航
2016/07/18 Javascript
VueJS全面解析
2016/11/10 Javascript
微信端开发--登录小程序步骤
2017/01/11 Javascript
JavaScript中英文字符长度统计方法示例【按照中文占2个字符】
2017/01/17 Javascript
微信小程序实现收货地址左滑删除
2020/11/18 Javascript
python时间整形转标准格式的示例分享
2014/02/14 Python
以Flask为例讲解Python的框架的使用方法
2015/04/29 Python
解析Python中的__getitem__专有方法
2016/06/27 Python
Python多线程经典问题之乘客做公交车算法实例
2017/03/22 Python
Python模块/包/库安装的六种方法及区别
2020/02/24 Python
python+requests接口压力测试500次,查看响应时间的实例
2020/04/30 Python
Pycharm 设置默认解释器路径和编码格式的操作
2021/02/05 Python
HTML5的一个显示电池状态的API简介
2015/06/18 HTML / CSS
trivago美国:全球最大的酒店价格比较网站
2018/01/18 全球购物
财务会计专业应届毕业生求职信
2013/10/18 职场文书
新闻编辑求职信
2014/04/09 职场文书
保护环境建议书400字
2014/05/13 职场文书
医院安全生产月活动总结
2014/07/05 职场文书
五四演讲稿范文
2014/09/03 职场文书
九一八事变演讲稿范文
2014/09/14 职场文书
优秀班主任材料
2014/12/16 职场文书
销售督导岗位职责
2015/04/10 职场文书
高中同学会致辞
2015/08/01 职场文书
2016天猫双十一广告语
2016/01/28 职场文书
《大禹治水》教学反思
2016/02/22 职场文书