JavaScript装饰者模式:动态扩展函数功能

作者:闭包旅人

时间:2026-10-30

浏览:228

本文介绍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设计模式与开发实践》

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章