学习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 相关文章推荐
javascript 三种编解码方式
Feb 01 Javascript
JQuery事件e参数的方法preventDefault()取消默认行为
Sep 26 Javascript
window.print打印指定div实例代码
Dec 13 Javascript
JS获取文本框,下拉框,单选框的值的简单实例
Feb 26 Javascript
jQuery中多个元素的Hover事件解决方案
Jun 12 Javascript
jQuery如何使用自动触发事件trigger
Nov 29 Javascript
Javascript基于jQuery UI实现选中区域拖拽效果
Nov 25 Javascript
javascript获取以及设置光标位置
Feb 16 Javascript
原生JS实现的多个彩色小球跟随鼠标移动动画效果示例
Feb 01 Javascript
JQuery获取元素尺寸、位置及页面滚动事件应用示例
May 14 jQuery
jQuery实现图片随机切换、抽奖功能(实例代码)
Oct 23 jQuery
vue 解决移动端弹出键盘导致页面fixed布局错乱的问题
Nov 06 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中常用编辑器推荐
2007/01/02 PHP
php获取文件夹路径内的图片以及分页显示示例
2014/03/11 PHP
PHP载入图像imagecreatefrom_gif_jpeg_png系列函数用法分析
2016/11/14 PHP
zend框架实现支持sql server的操作方法
2016/12/08 PHP
PHP基于PDO调用sqlserver存储过程通用方法【基于Yii框架】
2017/10/07 PHP
php中加密解密DES类的简单使用方法示例
2020/03/26 PHP
一个很酷的拖动层的js类,兼容IE及Firefox
2009/06/23 Javascript
浅析Js(Jquery)中,字符串与JSON格式互相转换的示例(直接运行实例)
2013/07/09 Javascript
JS中实现replaceAll的方法(实例代码)
2013/11/12 Javascript
JavaScript实现url地址自动检测并添加URL链接示例代码
2013/11/12 Javascript
JavaScript中最简洁的编码html字符串的方法
2014/10/11 Javascript
JavaScript使用cookie记录临时访客信息的方法
2015/04/07 Javascript
JS实现带鼠标效果的头像及文章列表代码
2015/09/27 Javascript
bootstrap组件之按钮式下拉菜单小结
2017/01/19 Javascript
JQueryEasyUI框架下的combobox的取值和绑定的方法
2017/01/22 Javascript
微信小程序封装http访问网络库实例代码
2017/05/24 Javascript
解决BootStrap Fileinput手机图片上传显示旋转问题
2017/06/01 Javascript
详谈表单重复提交的三种情况及解决方法
2017/08/16 Javascript
Vue2.0 axios前后端登陆拦截器(实例讲解)
2017/10/27 Javascript
详解NODEJS基于FFMPEG视频推流测试
2017/11/17 NodeJs
原生js实现获取form表单数据代码实例
2019/03/27 Javascript
vue改变对象或数组时的刷新机制的方法总结
2019/04/24 Javascript
python实现每次处理一个字符的三种方法
2014/10/09 Python
Python 2.7.x 和 3.x 版本的重要区别小结
2014/11/28 Python
Python里字典的基本用法(包括嵌套字典)
2019/02/27 Python
PyCharm第一次安装及使用教程
2020/01/08 Python
使用Tensorflow将自己的数据分割成batch训练实例
2020/01/20 Python
Python 实现黑客帝国中的字符雨的示例代码
2020/02/20 Python
win10下opencv-python特定版本手动安装与pip自动安装教程
2020/03/05 Python
Python开发.exe小工具的详细步骤
2021/01/27 Python
canvas粒子动画背景的实现示例
2018/09/03 HTML / CSS
html5 canvas合成海报所遇问题及解决方案总结
2017/08/03 HTML / CSS
销售会计工作职责
2013/12/02 职场文书
完美的中文自荐信
2014/05/24 职场文书
大专生求职信
2014/06/29 职场文书
大学生暑期实践报告之企业经营管理
2019/08/08 职场文书