轻松掌握JavaScript装饰者模式


Posted in Javascript onAugust 27, 2016

在传统的面向对象语言中,给对象添加功能常常使用继承的方式,但继承的方式会带来问题:当父类改变时,他的所有子类都将随之改变。 

当JavaScript脚本运行时,在一个对象中(或他的原型上)增加行为会影响该对象的所有实例, 

装饰者是一种实现继承的替代方案,它通过重载方法的形式添加新功能,该模式可以在被装饰者前面(before)或者后面(after)加上自己的行为以达到特定的目的。 

装饰者模式是为已有功能动态地添加更多功能的一种方式,把每个要装饰的功能放在单独的函数里,然后用该函数包装所要装饰的已有函数对象,因此,当需要执行特殊行为的时候,调用代码就可以根据需要有选择地、按顺序地使用装饰功能来包装对象。优点是把类(函数)的核心职责和装饰功能区分开了。 

我们可以定义工具函数,如下:

Function.prototype.before = function (beforeFn) {
  var self = this; //保存原函数的引用
  return function () { //返回包含了新函数和原函数的代理函数
    beforeFn.apply(this,arguments); //执行新函数,且保证this不被劫持
    return self.apply(this,arguments); //执行原函数,并返回原函数的执行结果,并保证this不被劫持
  }
};
Function.prototype.after = function (afterFn) {
  var self = this;
  return function () {
    var ret = self.apply(this,arguments);
    afterFn.apply(this,arguments);
    return ret;
  }
};

这里的参数beforeFn、afterFn即为要为原函数扩展新功能的新函数(添加装饰),它们的唯一区别是执行顺序的不同。如果不想污染Function的原型,可以用下面的方法:

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;
  }
};

例子:给HTTP请求中带上一个参数防止CSRF攻击

var ajax = function (type, url, param) {
  console.log(param); //发送ajax请求代码略...
};
var beforeFn = function (type, url, param) {
  param.Token = 'Token';
};
ajax = ajax.before(beforeFn);
ajax('get','http://...com/userinfo',{name:'SuFa'});
//{ name: 'SuFa', Token: 'Token' }

通过给ajax函数动态装饰上Token参数,而不是直接在原函数上修改参数,保证了ajax函数仍然是一个纯净的函数,提高了它的可复用性,它可在无需做任何修改的情况下直接拿到别的项目中使用。 

例子:表单验证(把验证输入和表单提交的代码分离开来,然后动态的把验证输入功能装饰到表单提交之前,这样一来,我们就可以把验证输入部分写成一个插件的形式,用在不同的项目中)

//验证输入函数
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();
};

参考文献: 《JavaScript模式》 《JavaScript设计模式与开发实践》

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于jQuery的图片大小自动适应实现代码
Nov 17 Javascript
JS获取当前日期时间并定时刷新示例
Mar 04 Javascript
javascript实现跨域的方法汇总
Jun 25 Javascript
jQuery页面加载初始化的3种方法(推荐)
Jun 02 Javascript
Bootstrap编写一个兼容主流浏览器的受众巨幕式风格页面
Jul 01 Javascript
vuejs项目打包之后的首屏加载优化及打包之后出现的问题
Apr 01 Javascript
Node.js 使用jade模板引擎的示例
May 11 Javascript
利用node 判断打开的是文件 还是 文件夹的实例
Jun 10 Javascript
vue 实现移动端键盘搜索事件监听
Nov 06 Javascript
layui 弹出层值回传解决方式
Nov 14 Javascript
swiperjs实现导航与tab页的联动
Dec 13 Javascript
elementui实现预览图片组件二次封装
Dec 29 Javascript
node.js实现快速截图
Aug 27 #Javascript
购物车前端开发(jQuery和bootstrap3)
Aug 27 #Javascript
利用Angularjs和Bootstrap前端开发案例实战
Aug 27 #Javascript
轻松掌握JavaScript享元模式
Aug 27 #Javascript
JavaScript编码风格指南(中文版)
Aug 26 #Javascript
JavaScript使用forEach()与jQuery使用each遍历数组时return false 的区别
Aug 26 #Javascript
ES6中的数组扩展方法
Aug 26 #Javascript
You might like
解决了Ajax、MySQL 和 Zend Framework 的乱码问题
2009/03/03 PHP
PHP中设置时区,记录日志文件的实现代码
2013/01/07 PHP
深入理解PHP类的自动载入机制
2016/09/16 PHP
详解Yii2 定制表单输入字段的标签和样式
2017/01/04 PHP
PHP中Session ID的实现原理实例分析
2019/08/17 PHP
在Laravel中使用MongoDB的方法示例
2019/11/11 PHP
利用PHP计算有多少小于当前数字的数字方法示例
2020/08/26 PHP
学习YUI.Ext 第六天--关于树TreePanel(Part 1)
2007/03/10 Javascript
js CSS操作方法集合
2008/10/31 Javascript
javascript showModalDialog 多层模态窗口实现页面提交及刷新的代码
2009/11/28 Javascript
javascript 实用的文字链提示框效果
2010/06/30 Javascript
页面只有一个text的时候,回车自动submit的解决方法
2010/08/12 Javascript
jQuery使用之处理页面元素用法实例
2015/01/19 Javascript
js实现内容显示并使用json传输数据
2016/03/16 Javascript
微信小程序 传值取值的几种方法总结
2017/01/16 Javascript
jquery实现数字输入框
2017/02/22 Javascript
vue v-model实现自定义样式多选与单选功能
2018/07/05 Javascript
解决element ui select下拉框不回显数据问题的解决
2019/02/20 Javascript
js实现窗口全屏示例详解
2019/09/17 Javascript
vue项目中定义全局变量、函数的几种方法
2019/11/08 Javascript
微信小程序图片自适应实现解析
2020/01/21 Javascript
antd中table展开行默认展示,且不需要前边的加号操作
2020/11/02 Javascript
[41:54]2018DOTA2亚洲邀请赛 4.1 小组赛A组加赛 TNC vs Liquid
2018/04/03 DOTA
Python编程对列表中字典元素进行排序的方法详解
2017/05/26 Python
Python Django2.0集成Celery4.1教程
2019/11/19 Python
Python selenium 自动化脚本打包成一个exe文件(推荐)
2020/01/14 Python
深入理解Tensorflow中的masking和padding
2020/02/24 Python
为什么相对PHP黑python的更少
2020/06/21 Python
详解利用canvas实现环形进度条的方法
2019/06/12 HTML / CSS
Nisbets法国:英国最大的厨房和餐饮设备供应商
2019/03/18 全球购物
标准大学生职业生涯规划书写作指南
2014/09/18 职场文书
家属答谢词
2015/01/05 职场文书
2015年语言文字工作总结
2015/07/23 职场文书
素质拓展训练感想
2015/08/07 职场文书
如何制定销售人员薪酬制度?
2019/07/09 职场文书
win11自动弹出虚拟键盘怎么关闭? Win11关闭虚拟键盘的技巧
2023/01/09 数码科技