使用函数装饰器巧妙实现数据埋点上报、表单验证

函数装饰器(AOP面向切面编程)的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些跟业务逻辑无关的功能通常包括日志统计,安全控制,异常处理等。把这些功能抽离出来后,再通过动态织入的方式掺入业务逻辑模块中

实现一个简单的AOP

js 复制代码
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
  }
}

// 使用
var func = function() {
  console.log(2);
}
func = func.before(function(){
  console.log(1);
}).after(function(){
  console.log(3);
})
func(); // 1 2 3

不污染原型的实现

js 复制代码
function before(fn, beforeFn) {
    return function() {
        beforeFn.apply(this, arguments)
        return fn.apply(this, arguments)
    }
}

function after(fn, afterFn) {
    return function() {
        var ret = fn.apply(this, arguments)
        afterFn(this, arguments)
        return ret
    }
}

应用实例一:数据埋点上报。

分离业务代码和数据统计代码,无论在什么语言中,都是AOP的经典应用之一。

html 复制代码
<button id="btnLogin">点击打开登录浮层</button>
js 复制代码
// 数据上报
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;
  }
}
var showLogin = function() {
  console.log('打开登录浮层');
}

// 依次输出:按钮点击之前上报  打开登录浮层  按钮点击之后上报
document.getElementById('btnLogin').onclick = showLogin.before(function(){
  console.log('按钮点击之前上报');
}).after(function() {
  console.log('按钮点击之后上报');
});

应用实例一:表单验证

html 复制代码
用户名:<input type="text" id="username">
密码:<input type="password" id="password">
<button id="loginBtn">登录</button>
js 复制代码
Function.prototype.before = function (beforeFn) {
  var _self = this;
  return function () {
    if(beforeFn.apply(this,arguments)===false) {
      // 未验证通过,不再执行原函数
      return ;
    }
    return _self.apply(this, arguments);
  }
}
var username = document.getElementById('username');
var password = document.getElementById('password');
var loginBtn = document.getElementById('loginBtn');
// 验证函数
var validate = function() {
  if(username.value === '') {
    console.log('用户名不能为空');
    return false;
  }
  if(password.value === '') {
    console.log('密码不能为空');
    return false;
  }
}
// 登录ajax
var formSubmit = function() {
  var params = {
    username: username,
    password: password
  }
  console.log('登录ajax...');
}
// 登录按钮点击
formSubmit = formSubmit.before(validate);
loginBtn.onclick = function() {
  formSubmit();
};

点个赞~~, 一起学习,一起进步

相关推荐
kyriewen1 小时前
今年裁了16万技术人——但字节前端岗反而涨了23%
前端·javascript·面试
用户059540174461 小时前
把 AI Agent 记忆存储验证从 40 分钟手测压到 3 分钟,pytest + Docker 这套组合太顶了
前端·css
stereohomology2 小时前
MS Edge很多事的一点是把地址栏复制的地址自动转标题文本
前端·edge
imaol12 小时前
链表 -- 环链表
java·前端·链表
imaol12 小时前
链表 -- 双向链表
java·前端·链表
东风破_2 小时前
大前端手里的 Next.js:从 #root 到 SEO,一份 HTML 的两种命运
前端·后端
IT_陈寒3 小时前
Vue的v-for不听话?我被这个Key的坑整懵了
前端·人工智能·后端
众人皆醒我独醉3 小时前
训练加速实战:Flash Attention、Gradient Checkpointing 与数据流水线
后端·面试·gpu
Loveyourself3 小时前
Claude Code Memory 总体系核心代码逐行解析
面试·agent
王林不想说话3 小时前
ES6 到 ES2026 全面进阶指南:新特性、原理、示例与工程落地
前端·javascript·面试