轻松掌握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如何判断表格同一列不同行input数据是否重复
May 14 Javascript
JQuery 控制内容长度超出规定长度显示省略号
May 23 Javascript
基于zepto.js实现仿手机QQ空间的大图查看组件ImageView.js详解
Mar 05 Javascript
JS实现简易图片轮播效果的方法
Mar 25 Javascript
ros::spin() 和 ros::spinOnce()函数的区别及详解
Oct 01 Javascript
js html css实现复选框全选与反选
Oct 09 Javascript
JavaScript实现数组降维详解
Jan 05 Javascript
微信小程序 下拉列表的实现实例代码
Mar 08 Javascript
ionic实现下拉刷新载入数据功能
May 11 Javascript
vue框架搭建之axios使用教程
Jul 11 Javascript
JavaScript实现动态添加、移除元素或属性的方法分析
Jan 03 Javascript
VUE页面中通过双击实现复制表格中内容的示例代码
Jun 11 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
php 获得汉字拼音首字母的函数
2009/08/01 PHP
php笔记之:有规律大文件的读取与写入的分析
2013/04/26 PHP
php数组添加元素方法小结
2014/12/20 PHP
PHP解决中文乱码
2017/04/28 PHP
php脚本守护进程原理与实现方法详解
2017/07/20 PHP
thinkphp集成前端脚手架Vue-cli的教程图解
2018/08/30 PHP
javascript 学习之旅 (2)
2009/02/05 Javascript
JQuery实现简单时尚快捷的气泡提示插件
2012/12/20 Javascript
jquery内置验证(validate)使用方法示例(表单验证)
2013/12/04 Javascript
Web 开发中Ajax的Session 超时处理方法
2017/01/19 Javascript
jquery代码规范让代码越来越好看
2017/02/03 Javascript
javascript 判断当前浏览器版本并判断ie版本
2017/02/17 Javascript
Vue.js如何实现路由懒加载浅析
2017/08/14 Javascript
AngularJS通过ng-Img-Crop实现头像截取的示例
2017/08/17 Javascript
jquery一键控制checkbox全选、反选或全不选
2017/10/16 jQuery
微信小程序实现打开内置地图功能【附源码下载】
2017/12/07 Javascript
详解Node.js中的Async和Await函数
2018/02/22 Javascript
jQuery中的类名选择器(.class)用法简单示例
2018/05/14 jQuery
JS使用Dijkstra算法求解最短路径
2019/01/17 Javascript
记录一次开发微信网页分享的步骤
2019/05/07 Javascript
详解Vue-cli3.X使用px2rem遇到的问题
2019/08/09 Javascript
node.js基础知识汇总
2020/08/25 Javascript
pycharm 使用心得(七)一些实用功能介绍
2014/06/06 Python
python matlibplot绘制3D图形
2018/07/02 Python
Pycharm取消py脚本中SQL识别的方法
2018/11/29 Python
python实现爬山算法的思路详解
2019/04/09 Python
python字符串替换第一个字符串的方法
2019/06/26 Python
python实现扫雷游戏
2020/03/03 Python
Python2.x与3​​.x版本有哪些区别
2020/07/09 Python
AC Lens:购买隐形眼镜
2017/02/26 全球购物
小学校园活动策划
2014/01/30 职场文书
运输服务质量承诺书
2014/03/27 职场文书
工作保证书
2015/01/17 职场文书
2015年幼儿园教研活动总结
2015/03/25 职场文书
关于antd tree 和父子组件之间的传值问题(react 总结)
2021/06/02 Javascript
Java SSH 秘钥连接mysql数据库的方法
2021/06/28 Java/Android