轻松掌握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方法添加回调函数一款插件的应用
Jan 21 Javascript
js计算两个时间之间天数差的实例代码
Nov 19 Javascript
javascript实现的右下角弹窗实例
Apr 24 Javascript
自动适应iframe右边的高度
Dec 22 Javascript
jquery uploadify如何取消已上传成功文件
Feb 08 Javascript
js+html制作简单日历的方法
Jun 27 Javascript
VueJS事件处理器v-on的使用方法
Sep 27 Javascript
vue 1.x 交互实现仿百度下拉列表示例
Oct 21 Javascript
javascript实现简易聊天室
Jul 12 Javascript
vue中v-for循环选中点击的元素并对该元素添加样式操作
Jul 17 Javascript
Vue中nprogress页面加载进度条的方法实现
Nov 13 Javascript
关于vue中如何监听数组变化
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
php 解决旧系统 查出所有数据分页的类
2012/08/27 PHP
php安全配置记录和常见错误梳理(总结)
2017/03/28 PHP
PHP的微信支付接口使用方法讲解
2019/03/08 PHP
PHP查找一列有序数组是否包含某值的方法
2020/02/07 PHP
Prototype Date对象 学习
2009/07/12 Javascript
js css样式操作代码(批量操作)
2009/10/09 Javascript
jquery 操作表格实现代码(多种操作打包)
2011/03/20 Javascript
捕获键盘事件(且兼容各浏览器)
2013/07/03 Javascript
把jquery 的dialog和ztree结合实现步骤
2013/08/02 Javascript
jquery使用淘宝接口跨域查询手机号码归属地实例
2013/11/28 Javascript
深入讲解AngularJS中的自定义指令的使用
2015/06/18 Javascript
动态生成的DOM不会触发onclick事件的原因及解决方法
2016/08/06 Javascript
JS中script标签defer和async属性的区别详解
2016/08/12 Javascript
利用jquery获取select下拉框的值
2016/11/23 Javascript
ReactJs设置css样式的方法
2017/06/08 Javascript
vue input 输入校验字母数字组合且长度小于30的实现代码
2018/05/16 Javascript
vue实现绑定事件的方法实例代码详解
2019/06/20 Javascript
JS前端知识点offset,scroll,client,冒泡,事件对象的应用整理总结
2019/06/27 Javascript
IE11下处理Promise及Vue的单项数据流问题
2019/07/24 Javascript
Vue最新防抖方案(必看篇)
2019/10/30 Javascript
微信小程序云开发获取文件夹下所有文件(推荐)
2019/11/14 Javascript
Python 列表理解及使用方法
2017/10/27 Python
浅谈python中对于json写入txt文件的编码问题
2018/06/07 Python
python读取一个目录下所有txt里面的内容方法
2018/06/23 Python
对Django 转发和重定向的实例详解
2019/08/06 Python
python如何实现不可变字典inmutabledict
2020/01/08 Python
python不到50行代码完成了多张excel合并的实现示例
2020/05/28 Python
HTML5 Canvas实现放大镜效果示例
2020/03/25 HTML / CSS
潘多拉珠宝美国官方网站:Pandora US
2020/06/18 全球购物
SIMON MILLER官网:洛杉矶的生活方式品牌
2020/10/19 全球购物
java程序员面试交流
2012/11/29 面试题
市场部经理岗位职责
2014/04/10 职场文书
竞争与合作演讲稿
2014/05/12 职场文书
金融与证券专业求职信
2014/06/22 职场文书
2015年审计人员工作总结
2015/05/26 职场文书
MySQL学习之基础命令实操总结
2022/03/19 MySQL