轻松掌握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 异步调用框架 (Part 4 - 链式调用)
Aug 04 Javascript
JavaScript中清空数组的三种方法分享
Apr 07 Javascript
实例代码详解jquery.slides.js
Nov 16 Javascript
js操作cookie保存浏览记录的方法
Dec 25 Javascript
初识angular框架后的所思所想
Feb 19 Javascript
JS组件Bootstrap实现弹出框效果代码
Apr 26 Javascript
Bootstrap php制作动态分页标签
Dec 23 Javascript
tablesorter.js表格排序使用方法(支持中文排序)
Feb 10 Javascript
JavaScript实现简单动态进度条效果
Apr 06 Javascript
js中对象和面向对象与Json介绍
Jan 21 Javascript
小程序Request的另类用法详解
Aug 09 Javascript
JS造成内存泄漏的几种情况实例分析
Mar 02 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
模仿OSO的论坛(五)
2006/10/09 PHP
Thinkphp连表查询及数据导出方法示例
2016/10/15 PHP
PHPExcel导出2003和2007的excel文档功能示例
2017/01/04 PHP
Laravel 5.5 的自定义验证对象/类示例代码详解
2017/08/29 PHP
2007/12/23更新创意无限,简单实用(javascript log)
2007/12/24 Javascript
Js 本页面传值实现代码
2009/05/17 Javascript
jquery得到font-size属性值实现代码
2013/09/30 Javascript
js实现遍历含有input的table实例
2015/12/07 Javascript
Angularjs中的事件广播 —全面解析$broadcast,$emit,$on
2016/05/17 Javascript
javascript获取以及设置光标位置
2017/02/16 Javascript
jquery实现楼层滚动效果
2018/01/01 jQuery
layer插件select选中默认值的方法
2018/08/14 Javascript
Vue动态面包屑功能的实现方法
2019/07/01 Javascript
使用原生JS实现滚轮翻页效果的示例代码
2020/05/31 Javascript
webpack 如何同时输出压缩和未压缩的文件的实现步骤
2020/06/05 Javascript
[50:29]2014 DOTA2华西杯精英邀请赛 5 24 DK VS iG
2014/05/26 DOTA
[02:43]2018DOTA2亚洲邀请赛主赛事首日TOP5
2018/04/04 DOTA
[33:28]完美世界DOTA2联赛PWL S3 PXG vs GXR 第三场 12.19
2020/12/24 DOTA
Python中__init__和__new__的区别详解
2014/07/09 Python
代码讲解Python对Windows服务进行监控
2018/02/11 Python
python实现画一颗树和一片森林
2018/06/25 Python
python实现朴素贝叶斯算法
2018/11/19 Python
利用Python实现手机短信监控通知的方法
2019/07/22 Python
在Python中os.fork()产生子进程的例子
2019/08/08 Python
如何使用Python破解ZIP或RAR压缩文件密码
2020/01/09 Python
Django 解决新建表删除后无法重新创建等问题
2020/05/21 Python
css3中单位px,em,rem,vh,vw,vmin,vmax的区别及浏览器支持情况
2016/12/06 HTML / CSS
Clarks鞋澳大利亚官方网站:Clarks Australia
2019/12/25 全球购物
住房公积金接收函
2014/01/09 职场文书
《藤野先生》教学反思
2014/02/19 职场文书
《梅兰芳学艺》教学反思
2014/02/24 职场文书
节能环保演讲稿
2014/08/28 职场文书
实习指导教师评语
2014/12/30 职场文书
卫生院义诊活动总结
2015/05/07 职场文书
奖学金申请书(范文)
2019/08/14 职场文书
HTML实现仿Windows桌面主题特效的实现
2022/06/28 HTML / CSS