轻松掌握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中最常用的继承模式 组合继承
Aug 12 Javascript
javascript实现将文件保存到本地方法汇总
Jul 26 Javascript
JS实现跟随鼠标的链接文字提示框效果
Aug 06 Javascript
jquery 动态增加删除行的简单实例(推荐)
Oct 12 Javascript
Javascript oop设计模式 面向对象编程简单实例介绍
Dec 13 Javascript
详解vue-cli中的ESlint配置文件eslintrc.js
Sep 25 Javascript
浅谈React中组件间抽象
Jan 27 Javascript
微信小程序中的店铺评分组件及vue中用svg实现的评分显示组件
Nov 16 Javascript
使用vue-cli webpack 快速搭建项目的代码
Nov 21 Javascript
ES6的异步终极解决方案分享
Jul 11 Javascript
JS出现404错误原理及解决方案
Jul 01 Javascript
vue组件冲突之引用另一个组件出现组件不显示的问题
Apr 13 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
长波有什么东西
2021/03/01 无线电
老机欣赏|中国60年代精品收音机
2021/03/02 无线电
php下获取Discuz论坛登录用户名、用户组、用户ID等信息的实现代码
2010/12/29 PHP
php记录代码执行时间(实现代码)
2013/07/05 PHP
PHP使用DOMDocument类生成HTML实例(包含常见标签元素)
2014/06/25 PHP
php实现在多维数组中查找特定value的方法
2015/07/29 PHP
一个用javascript写的select支持上下键、首字母筛选以及回车取值的功能
2009/09/09 Javascript
document节点对象的获取方式示例介绍
2013/12/24 Javascript
JS实现alert中显示换行的方法
2015/12/17 Javascript
获取input标签的所有属性的方法
2016/06/28 Javascript
javascript实现的上下无缝滚动效果
2016/09/19 Javascript
jquery uploadify如何取消已上传成功文件
2017/02/08 Javascript
jQuery文字轮播特效
2017/02/12 Javascript
JS实现直接运行html代码的方法
2017/03/13 Javascript
原生JavaScrpit中异步请求Ajax实现方法
2017/11/03 Javascript
vue init失败简单解决方法(终极版)
2017/12/22 Javascript
React 实现拖拽功能的示例代码
2019/01/06 Javascript
vue 表单之通过v-model绑定单选按钮radio
2019/05/13 Javascript
微信小程序之左右布局的实现代码
2019/12/13 Javascript
浅谈Python中列表生成式和生成器的区别
2015/08/03 Python
CentOS中升级Python版本的方法详解
2017/07/10 Python
Python 确定多项式拟合/回归的阶数实例
2018/12/29 Python
Python中出现IndentationError:unindent does not match any outer indentation level错误的解决方法
2020/04/18 Python
python调用pyaudio使用麦克风录制wav声音文件的教程
2019/06/26 Python
Python中调用其他程序的方式详解
2019/08/06 Python
Python3视频转字符动画的实例代码
2019/08/29 Python
Python+logging输出到屏幕将log日志写入文件
2020/11/11 Python
美国木工工具和用品商店:Woodcraft
2019/10/30 全球购物
军训自我鉴定怎么写
2014/02/13 职场文书
村容村貌整治方案
2014/05/21 职场文书
送温暖献爱心活动总结
2014/07/08 职场文书
机关干部三严三实心得体会
2014/10/13 职场文书
夫妻双方自愿离婚协议书怎么写
2014/12/01 职场文书
公司档案管理制度
2015/08/05 职场文书
社区服务活动感想
2015/08/11 职场文书
2016年优秀少先队辅导员事迹材料
2016/02/26 职场文书