轻松掌握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 相关文章推荐
JS option location 页面跳转实现代码
Dec 27 Javascript
实测jquery data()如何存值
Aug 18 Javascript
深入理解JavaScript系列(41):设计模式之模板方法详解
Mar 04 Javascript
jquery实现用户打分评分特效
May 28 Javascript
使用Promise链式调用解决多个异步回调的问题
Jan 15 Javascript
js实现方块上下左右移动效果
Aug 17 Javascript
JS基于设计模式中的单例模式(Singleton)实现封装对数据增删改查功能
Feb 06 Javascript
webpack 插件html-webpack-plugin的具体使用
Apr 09 Javascript
简单的三步vuex入门
May 20 Javascript
微信小程序实现吸顶特效
Jan 08 Javascript
javascript设计模式 ? 桥接模式原理与应用实例分析
Apr 13 Javascript
vue使用swiper实现左右滑动切换图片
Oct 16 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
Terran兵种介绍
2020/03/14 星际争霸
用PHP实现多级树型菜单
2006/10/09 PHP
php中在PDO中使用事务(Transaction)
2011/05/14 PHP
PHP用SAX解析XML的实现代码与问题分析
2011/08/22 PHP
php+mysql实现无限级分类
2015/11/11 PHP
PHP入门教程之PHP操作MySQL的方法分析
2016/09/11 PHP
Laravel 5.4.36中session没有保存成功问题的解决
2018/02/19 PHP
当某个文本框成为焦点时即清除文本框内容
2014/04/28 Javascript
jQuery实现的多屏图像图层切换效果实例
2015/05/07 Javascript
Spring MVC中Ajax实现二级联动的简单实例
2016/07/06 Javascript
学习Angular中作用域需要注意的坑
2016/08/17 Javascript
详解在Angularjs中ui-sref和$state.go如何传递参数
2017/04/24 Javascript
JavaScript该如何学习 怎样轻松学习JavaScript
2017/06/12 Javascript
使用prop解决一个checkbox选中后再次选中失效的问题
2017/07/05 Javascript
jquery-file-upload 文件上传带进度条效果
2017/11/21 jQuery
Vue 前端实现登陆拦截及axios 拦截器的使用
2019/07/17 Javascript
node.js中 mysql 增删改查操作及async,await处理实例分析
2020/02/11 Javascript
vue中的双向数据绑定原理与常见操作技巧详解
2020/03/16 Javascript
[58:23]LGD vs TNC 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
Python中类的继承代码实例
2014/10/28 Python
Python装饰器用法实例总结
2018/02/07 Python
详谈Python3 操作系统与路径 模块(os / os.path / pathlib)
2018/04/26 Python
python 两个数据库postgresql对比
2019/10/21 Python
将 Ubuntu 16 和 18 上的 python 升级到最新 python3.8 的方法教程
2020/03/11 Python
python批量处理多DNS多域名的nslookup解析实现
2020/06/28 Python
python 基于opencv操作摄像头
2020/12/24 Python
python反编译教程之2048小游戏实例
2021/03/03 Python
HTML5 Blob对象的具体使用
2020/05/22 HTML / CSS
三星新西兰官网:Samsung新西兰
2019/03/05 全球购物
投标担保书范文
2014/04/02 职场文书
保护环境倡议书100字
2014/05/19 职场文书
幼儿园小班教师个人工作总结
2015/02/06 职场文书
心理健康教育主题班会
2015/08/13 职场文书
如何使用Maxwell实时同步mysql数据
2021/04/08 MySQL
Centos环境下Postgresql 安装配置及环境变量配置技巧
2021/05/18 PostgreSQL
Mysql官方性能测试工具mysqlslap的使用简介
2021/05/21 MySQL