轻松掌握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高级程序设计(第3版)学习笔记2 js基础语法
Oct 11 Javascript
jquery设置控件位置的方法
Aug 21 Javascript
javascript与cookie 的问题详解
Nov 11 Javascript
让IE8浏览器支持function.bind()方法
Oct 16 Javascript
javascript常用函数归纳整理
Oct 31 Javascript
jQuery实现向下滑出的平滑下拉菜单效果
Aug 21 Javascript
node简单实现一个更改头像功能的示例
Dec 29 Javascript
mpvue+vuex搭建小程序详细教程(完整步骤)
Sep 30 Javascript
Node.js JSON模块用法实例分析
Jan 04 Javascript
JS实现获取数组中最大值或最小值功能示例
Mar 02 Javascript
解决layui的form里的元素进行动态生成,验证失效的问题
Sep 14 Javascript
vue引入Excel表格插件的方法
Apr 28 Vue.js
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
牡丹941资料
2021/03/01 无线电
一个没有MYSQL数据库支持的简易留言本的编写
2006/10/09 PHP
PHP DataGrid 实现代码
2009/08/12 PHP
PHP5.3.1 不再支持ISAPI
2010/01/08 PHP
基于Snoopy的PHP近似完美获取网站编码的代码
2011/10/23 PHP
PHP全局使用Laravel辅助函数dd
2019/12/26 PHP
一个用js实现控制台控件的代码
2007/09/04 Javascript
Jquery 快速构建可拖曳的购物车DragDrop
2009/11/30 Javascript
在页面上用action传递参数到后台出现乱码的解决方法
2013/12/31 Javascript
js实现浏览本地文件并显示扩展名的方法
2015/08/17 Javascript
值得分享的Bootstrap Table使用教程
2016/11/23 Javascript
js实现的简练高效拖拽功能示例
2016/12/21 Javascript
Angular-Ui-Router+ocLazyLoad动态加载脚本示例
2017/03/02 Javascript
关于vue中的ajax请求和axios包问题
2018/04/19 Javascript
React.js绑定this的5种方法(小结)
2018/06/05 Javascript
OpenLayers3实现鼠标移动显示坐标
2020/09/25 Javascript
详解Python中dict与set的使用
2015/08/10 Python
Python中%r和%s的详解及区别
2017/03/16 Python
使用python进行文本预处理和提取特征的实例
2018/06/05 Python
浅谈django rest jwt vue 跨域问题
2018/10/26 Python
浅谈对pytroch中torch.autograd.backward的思考
2019/12/27 Python
Python图片处理模块PIL操作方法(pillow)
2020/04/07 Python
CSS3实现滚动条动画效果代码分享
2016/08/03 HTML / CSS
前端canvas水印快速制作(附完整代码)
2019/09/19 HTML / CSS
C#和SQL Server的面试题
2016/08/12 面试题
软件测试笔试题
2012/10/25 面试题
一套软件开发工程师笔试题
2015/05/18 面试题
七夕相亲活动策划方案
2014/08/31 职场文书
公司股份合作协议书
2014/12/07 职场文书
2015年国际护士节演讲稿
2015/03/18 职场文书
庆祝教师节主题班会
2015/08/17 职场文书
盘点2020年适合农村地区创业的项目
2019/10/16 职场文书
在pyCharm中下载第三方库的方法
2021/04/18 Python
解决golang结构体tag编译错误的问题
2021/05/02 Golang
MongoDB数据库的安装步骤
2021/06/18 MongoDB
SpringBoot读取Resource下文件的4种方法
2021/07/02 Java/Android