学习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读取RSS数据
Jan 20 Javascript
js生成验证码并直接在前端判断
May 15 Javascript
你所不了解的javascript操作DOM的细节知识点(一)
Jun 17 Javascript
jquery实现二级导航下拉菜单效果
Dec 18 Javascript
jQuery实现的鼠标经过时变宽的效果(附demo源码)
Apr 28 Javascript
深入浅出 jQuery中的事件机制
Aug 23 Javascript
Javascript实现从小到大的数组转换成二叉搜索树
Jun 13 Javascript
实现一个完整的Node.js RESTful API的示例
Sep 29 Javascript
vue购物车插件编写代码
Nov 27 Javascript
解决vue中post方式提交数据后台无法接收的问题
Aug 11 Javascript
详解vue 中 scoped 样式作用域的规则
Sep 14 Javascript
vue3不同环境下实现配置代理
May 25 Vue.js
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 404错误页面实现代码
2009/06/22 PHP
PHP 获取文件路径(灵活应用__FILE__)
2013/02/15 PHP
360通用php防护代码(使用操作详解)
2013/06/18 PHP
php实现把数组按指定的个数分隔
2014/02/17 PHP
PHP实现的抓取小说网站内容功能示例
2019/06/27 PHP
Thinkphp5.0 框架Model模型简单用法分析
2019/10/11 PHP
Javascript实现重力弹跳拖拽运动效果示例
2013/06/28 Javascript
jquery模拟SELECT下拉框取值效果
2013/10/23 Javascript
Javascript改变CSS样式(局部和全局)
2013/12/18 Javascript
document.forms[].submit()使用介绍
2014/02/19 Javascript
js实现的GridView即表头固定表体有滚动条且可滚动
2014/02/19 Javascript
javascript判断是否按回车键并解决浏览器之间的差异
2014/05/13 Javascript
JavaScript遍历table表格中的某行某列并打印其值
2014/07/08 Javascript
JavaScript函数定义的常见注意事项小结
2014/09/16 Javascript
JavaScript知识点总结(十)之this关键字
2016/05/31 Javascript
Centos7 中 Node.js安装简单方法
2016/11/02 Javascript
Angular.js中控制器之间的传值详解
2017/04/24 Javascript
详解vue-cli + webpack 多页面实例应用
2017/04/25 Javascript
详解vue slot插槽的使用方法
2017/06/13 Javascript
详解javascript函数写法大全
2019/03/25 Javascript
微信小程序复选框实现多选一功能过程解析
2020/02/14 Javascript
使用pandas将numpy中的数组数据保存到csv文件的方法
2018/06/14 Python
Pytoch之torchvision.transforms图像变换实例
2019/12/30 Python
python 批量下载bilibili视频的gui程序
2020/11/20 Python
Python Selenium破解滑块验证码最新版(GEETEST95%以上通过率)
2021/01/29 Python
TobyDeals美国:在电子产品上获得最好的优惠和折扣
2019/08/11 全球购物
财务人员个人自荐信范文
2013/09/26 职场文书
优秀中专生推荐信
2013/11/17 职场文书
关于赌博的检讨书
2014/01/08 职场文书
教师旷工检讨书
2014/01/18 职场文书
端午节演讲稿
2014/05/23 职场文书
省级优秀毕业生主要事迹
2014/05/29 职场文书
第二批党的群众路线教育实践活动个人对照检查材料
2014/09/23 职场文书
单位推荐信范文
2015/03/27 职场文书
2016年秋季运动会加油稿
2015/12/21 职场文书
公安纪律作风整顿心得体会
2016/01/23 职场文书