轻松掌握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 相关文章推荐
JavaScript入门教程(7) History历史对象
Jan 31 Javascript
javascript AutoScroller 函数类
May 29 Javascript
心扬JS分页函数代码
Sep 10 Javascript
在Ajax中使用Flash实现跨域数据读取的实现方法
Dec 02 Javascript
jQuery 网易相册鼠标移动显示隐藏效果实现代码
Mar 31 Javascript
jquery插件jquery.beforeafter.js实现左右拖拽分隔条对比图片的方法
Aug 07 Javascript
JavaScript程序中实现继承特性的方式总结
Jun 24 Javascript
node.js实现的装饰者模式示例
Sep 06 Javascript
浅谈Vuex@2.3.0 中的 state 支持函数申明
Nov 22 Javascript
Angular Excel 导入与导出的实现代码
Apr 17 Javascript
微信小程序按钮点击跳转页面详解
May 06 Javascript
vue实现简单计算商品价格
Sep 14 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
老机欣赏|中国60年代精品收音机
2021/03/02 无线电
利用文件属性结合Session实现在线人数统计
2006/10/09 PHP
ThinkPHP和UCenter接口冲突的解决方法
2016/07/25 PHP
JavaScript 判断判断某个对象是Object还是一个Array
2010/01/28 Javascript
js 绑定键盘鼠标事件示例代码
2014/02/12 Javascript
JavaScript在网页中画圆的函数arc使用方法
2015/11/13 Javascript
基于jquery实现图片上传本地预览功能
2016/01/08 Javascript
基于jquery实现动态竖向柱状条特效
2016/02/12 Javascript
webpack+vue.js实现组件化详解
2016/10/12 Javascript
JavaScript利用正则表达式替换字符串中的内容
2016/12/12 Javascript
JavaScript调试的多个必备小Tips
2017/01/15 Javascript
Vue用v-for给循环标签自身属性添加属性值的方法
2018/10/18 Javascript
微信小程序 数据缓存实现方法详解
2019/08/26 Javascript
node.js中Buffer缓冲器的原理与使用方法分析
2019/11/23 Javascript
python线程锁(thread)学习示例
2013/12/04 Python
python快速查找算法应用实例
2014/09/26 Python
让 python 命令行也可以自动补全
2014/11/30 Python
Python获取当前公网ip并自动断开宽带连接实例代码
2018/01/12 Python
python2.7实现爬虫网页数据
2018/05/25 Python
Python查找第n个子串的技巧分享
2018/06/27 Python
python 定时器,轮询定时器的实例
2019/02/20 Python
网易2016研发工程师编程题 奖学金(python)
2019/06/19 Python
django将网络中的图片,保存成model中的ImageField的实例
2019/08/07 Python
Python 面向对象静态方法、类方法、属性方法知识点小结
2020/03/09 Python
Python实现井字棋小游戏
2020/03/09 Python
Pytorch转keras的有效方法,以FlowNet为例讲解
2020/05/26 Python
Python坐标轴操作及设置代码实例
2020/06/04 Python
澳大利亚百货商店中销量第一的商务衬衫品牌:Van Heusen
2018/07/26 全球购物
婴儿地球:Baby Earth
2018/12/25 全球购物
介绍一下Linux中的链接
2016/06/05 面试题
法律专业应届本科毕业生求职信
2013/10/25 职场文书
幼儿园师德师风学习材料
2014/05/29 职场文书
无罪辩护词范文
2015/05/21 职场文书
先进党支部事迹材料2016
2016/02/26 职场文书
Jupyter notebook 输出部分显示不全的解决方案
2021/04/24 Python
python保存图片的四个常用方法
2022/02/28 Python