轻松掌握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中增加参数与Json转换代码
Nov 20 Javascript
AJAX异步从优酷专辑中采集所有视频及信息(JavaScript代码)
Nov 20 Javascript
ASP.NET jQuery 实例11 通过使用jQuery validation插件简单实现用户登录页面验证功能
Feb 03 Javascript
js实现俄罗斯方块小游戏分享
Jan 31 Javascript
jquery获取当前点击对象的value方法
Feb 28 Javascript
JS设置cookie、读取cookie、删除cookie
Apr 17 Javascript
jQuery实现点击任意位置弹出层外关闭弹出层效果
Oct 19 Javascript
javascript 实现动态侧边栏实例详解
Nov 11 Javascript
深入学习Bootstrap表单
Dec 13 Javascript
jQuery实现简单的滑动导航代码(移动端)
May 22 jQuery
详解webpack+express多页站点开发
Dec 22 Javascript
javascript实现贪吃蛇经典游戏
Apr 10 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
桌面中心(四)数据显示
2006/10/09 PHP
php使用多个进程同时控制文件读写示例
2014/02/28 PHP
php将textarea数据提交到mysql出现很多空格的解决方法
2014/12/19 PHP
VPS中使用LNMP安装WordPress教程
2014/12/28 PHP
php实现通用的从数据库表读取数据到数组的函数实例
2015/03/21 PHP
PHP explode()函数的几个应用和implode()函数有什么区别
2015/11/05 PHP
thinkphp跨库操作的简单代码实例
2016/09/22 PHP
php检测mysql表是否存在的方法小结
2017/07/20 PHP
yii2中LinkPager增加总页数和总记录数的实例
2017/08/28 PHP
Linux下 php7安装redis的方法
2018/11/01 PHP
javascript 显示当前系统时间代码
2009/12/28 Javascript
jQuery timers计时器简单应用说明
2010/10/28 Javascript
jQuery EasyUI API 中文文档 - Spinner微调器使用
2011/10/21 Javascript
JavaScript中“过于”犀利地for/in循环使用示例
2013/10/22 Javascript
JS动态添加与删除select中的Option对象(示例代码)
2013/12/25 Javascript
vue bootstrap小例子一枚
2017/06/09 Javascript
用ES6的class模仿Vue写一个双向绑定的示例代码
2018/04/20 Javascript
如何解决React官方脚手架不支持Less的问题(小结)
2018/09/12 Javascript
vue elementUI table表格数据 滚动懒加载的实现方法
2019/04/04 Javascript
layui将table转化表单显示的方法(即table.render转为表单展示)
2019/09/24 Javascript
js实现百度登录窗口拖拽效果
2020/03/19 Javascript
安装多版本Vue-CLI的实现方法
2020/03/24 Javascript
解决在Vue中使用axios POST请求变成OPTIONS的问题
2020/08/14 Javascript
Python将阿拉伯数字转换为罗马数字的方法
2015/07/10 Python
python实现一个简单的并查集的示例代码
2018/03/19 Python
pandas分别写入excel的不同sheet方法
2018/12/11 Python
Python: glob匹配文件的操作
2020/12/11 Python
纽约的奢华内衣店:Journelle
2016/07/29 全球购物
阿里巴巴英国:Alibaba英国
2019/12/11 全球购物
中专自我鉴定范文
2013/10/16 职场文书
中介业务员岗位职责
2014/04/09 职场文书
如何签定毕业生就业协议书
2014/09/28 职场文书
2015年消防工作总结
2015/04/24 职场文书
创业计划书之儿童理发店
2019/09/27 职场文书
JS新手入门数组处理的实用方法汇总
2021/04/07 Javascript
Oracle数据库中通用的函数实例详解
2022/03/25 Oracle