学习JavaScript设计模式之装饰者模式


Posted in Javascript onJanuary 19, 2016

有时我们不希望某个类天生就非常庞大,一次性包含许多职责。那么我们就可以使用装饰着模式。
装饰着模式可以动态地给某个对象添加一些额外的职责,从而不影响这个类中派生的其他对象。
装饰着模式将一个对象嵌入另一个对象之中,实际上相当于这个对象被另一个对象包装起来,形成一条包装链。

一、不改动原函数的情况下,给该函数添加些额外的功能

1. 保存原引用

window.onload = function() {
  console.log(1);
};

var _onload = window.onload || function() {};

window.onload = function() {
  _onload();
  console.log(2);
}

问题:
(1)必须维护中间变量
(2)可能遇到this被劫持问题
在window.onload的例子中没有这个烦恼,是因为调用普通函数_onload时,this也指向window,跟调用window.onload时一样。

2. this被劫持:

var _getElementById = document.getElementById;
document.getElementById = function(id) {
  console.log(1);
  return _getElementById(id);
}

return _getElementById(id); // 报错“Uncaught TypeError: Illegal invocation”

因为_getElementById是全局函数,当调用全局函数时,this是指向window的,而document.getElementById中this预期指向document。

3. 解决this被劫持:

var _getElementById = document.getElementById;
document.getElementById = function(id) {
  console.log(1);
  return _getElementById.call(document, id);
}

二、用AOP装饰函数

/* 让新添加的函数在原函数之前执行(前置装饰)*/
Function.prototype.before = function(beforefn) {
  var _self = this;
  return function() {
    beforefn.apply(this, arguments);  // 新函数接收的参数会被原封不动的传入原函数
    return _self.apply(this, arguments);
  };
};
/* 让新添加的函数在原函数之后执行(后置装饰)*/
Function.prototype.after = function(afterfn) {
  var _self = this;
  return function() {
    var ret = _self.apply(this, arguments);
    afterfn.apply(this, arguments);
    return ret;
  };
};
document.getElementById = document.getElementById.before(function() {
  console.log(1);
});

三、避免污染原型

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;
  };
};

document.getElementById = before(document.getElementById, function(){
  console.log(1);
});

四、示例?插件式的表单验证

结合《学习JavaScript设计模式之策略模式》中的【表单验证】,运用到ajax提交数据验证,效果很棒!

修改上述before方法

var before = function(fn, beforefn) {
  return function() {
    if(beforefn.apply(this, arguments) === false) {
      // beforefn返回false,直接return,不执行后面的原函数
      return;
    }
    return fn.apply(this, arguments);
  };
};
/* 模拟数据验证*/
var validate = function() {
  if(username === "") {
    console.log("验证失败!");
    return false;
  }
  return true;
}
/* 模拟ajax提交*/
var formSubmit = function() {
  console.log("提交!!!");
}
username = 1;
formSubmit = before(formSubmit, validate); // 提交!!!
formSubmit();

username = "";
formSubmit = before(formSubmit, validate); // 验证失败!
formSubmit();

五、装饰者模式和代理模式

相同点:这两种模式都描述了怎么为对象提供一定程度上的间接引用,它们的实现部分都保留了对另外一个对象的引用,并且向那个对象发送请求。
区别:
(1)代理模式:当直接访问本地不方便或者不符合需求时,为这个本体提供一个替代者。本地定义关键功能,而代理提供或拒绝对它的访问,或者在访问本体之前走一些额外的事情。(其做的事情还是跟本体一样)
(2)装饰者模式:为对象动态加入行为。(一开始不能确定对象的全部功能,实实在在的为对象添加新的职责和行为)

希望本文所述对大家学习javascript程序设计有所帮助。

Javascript 相关文章推荐
javascript中的关于类型转换的性能优化
Dec 14 Javascript
js 三级关联菜单效果实例
Aug 13 Javascript
JS获取URL中的参数数据
Dec 05 Javascript
jQuery选择器全面总结
Jan 06 Javascript
JavaScript实现可拖拽的拖动层Div实例
Aug 05 Javascript
Avalon中文长字符截取、关键字符隐藏、自定义过滤器
May 18 Javascript
vue实现简单实时汇率计算功能
Jan 15 Javascript
js html实现计算器功能
Nov 13 Javascript
node全局变量__dirname与__filename的区别
Jan 14 Javascript
js仿360开机效果
Dec 26 Javascript
在 Vue 中使用 JSX 及使用它的原因浅析
Feb 10 Javascript
vue使用v-model进行跨组件绑定的基本实现方法
Apr 28 Vue.js
jQuery事件绑定用法详解(附bind和live的区别)
Jan 19 #Javascript
浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入
Jan 19 #Javascript
js实现有过渡渐变效果的图片轮播相册(兼容IE,ff)
Jan 19 #Javascript
jquery 重写 ajax提交并判断权限后 使用load方法报错解决方法
Jan 19 #Javascript
学习JavaScript设计模式之享元模式
Jan 18 #Javascript
纯JavaScript基于notie.js插件实现消息提示特效
Jan 18 #Javascript
学习JavaScript设计模式之责任链模式
Jan 18 #Javascript
You might like
全国FM电台频率大全 - 14 江西省
2020/03/11 无线电
晶体管来复再生式二管收音机
2021/03/02 无线电
PHP错误Allowed memory size of 67108864 bytes exhausted的3种解决办法
2014/07/28 PHP
Yii中CGridView关联表搜索排序方法实例详解
2014/12/03 PHP
php单一接口的实现方法
2015/06/20 PHP
Yii CFileCache 获取不到值的原因分析
2017/02/08 PHP
php表单文件iframe异步上传实例讲解
2017/07/26 PHP
Laravel监听数据库访问,打印SQL的例子
2019/10/24 PHP
用js实现的一个Flash滚动轮换显示图片代码生成器
2007/03/14 Javascript
IE与firefox之jquery用法区别
2008/10/03 Javascript
js 获取radio按钮值的实例
2013/08/17 Javascript
Javascript中数组sort和reverse用法分析
2014/12/30 Javascript
JavaScript中数据结构与算法(三):链表
2015/06/19 Javascript
JavaScript代码实现图片循环滚动效果
2020/03/19 Javascript
探讨AngularJs中ui.route的简单应用
2016/11/16 Javascript
解决Angular.Js与Django标签冲突的方案
2016/12/20 Javascript
使用gulp搭建本地服务器并实现模拟ajax
2017/04/05 Javascript
JS精确判断数据类型代码实例
2019/12/18 Javascript
JS中==、===你分清楚了吗
2020/03/04 Javascript
vue实现购物车案例
2020/05/30 Javascript
JS闭包原理及其使用场景解析
2020/12/03 Javascript
11个Javascript小技巧帮你提升代码质量(小结)
2020/12/28 Javascript
Vue实现圆环进度条的示例
2021/02/06 Vue.js
使用Python爬了4400条淘宝商品数据,竟发现了这些“潜规则”
2018/03/23 Python
Django rest framework工具包简单用法示例
2018/07/20 Python
python面向对象法实现图书管理系统
2019/04/19 Python
Python图像读写方法对比
2020/11/16 Python
基于ccs3的timeline时间线实现方法
2020/04/30 HTML / CSS
教师个人的自我评价分享
2014/01/02 职场文书
财务管理职业生涯规划书
2014/02/26 职场文书
秋季运动会开幕词
2015/01/28 职场文书
学习与创新自我评价
2015/03/09 职场文书
致运动员赞词
2015/07/22 职场文书
2016春季校长开学典礼致辞
2015/11/26 职场文书
如何书写你的职业生涯规划书?
2019/06/27 职场文书
导游词之广东佛山(南风古灶)
2019/09/24 职场文书