本文介绍JavaScript中的装饰者模式,通过高阶函数在原有函数前后动态添加新功能。文章提供了不污染原型链的工具函数实现,并演示了如何在HTTP请求中动态注入Token以防御CSRF攻击,以及如何将表单验证逻辑作为插件动态装饰到提交函数之前,实现代码解耦与复用。
装饰者模式概述
在传统的面向对象编程中,为对象添加功能通常依赖继承机制。然而,这种方式存在显著缺陷:一旦父类定义发生变更,其所有子类都会受到影响,导致代码维护困难且耦合度高。
在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代表用于扩展原函数功能的新函数(即装饰器)。两者的核心区别在于执行时序: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;
}
};
应用场景:CSRF防御
以下是一个具体应用场景:在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设计模式与开发实践》
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。