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

函数装饰器(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();
};

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

相关推荐
徐小夕1 小时前
JitWord Office预览引擎:如何用Vue3+Node.js打造丝滑的PDF/Excel/PPT嵌入方案
前端·vue.js·github
晴殇i1 小时前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
孟陬1 小时前
国外技术周刊 #1:Paul Graham 重新分享最受欢迎的文章《创作者的品味》、本周被划线最多 YouTube《如何在 19 分钟内学会 AI》、为何我不
java·前端·后端
BER_c1 小时前
前端权限校验最佳实践:一个健壮的柯里化工具函数
前端·javascript
兆子龙1 小时前
别再用 useState / data 管 Tabs 的 activeKey 了:和 URL 绑定才香
前端·架构
sudo_jin1 小时前
前端包管理器演进史:为什么 npm 之后,Yarn 和 pnpm 成了新宠?
前端·npm
绝无仅有2 小时前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有2 小时前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
敲敲敲敲暴你脑袋2 小时前
写个添加注释的vscode插件
javascript·typescript·visual studio code
叁两2 小时前
用opencode打造全自动公众号写作流水线,AI 代笔太香了!
前端·人工智能·agent