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

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

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

相关推荐
tsumikistep39 分钟前
【前后端】接口文档与导入
前端·后端·python·硬件架构
行走的陀螺仪1 小时前
.vscode 文件夹配置详解
前端·ide·vscode·编辑器·开发实践
2503_928411562 小时前
11.24 Vue-组件2
前端·javascript·vue.js
Bigger2 小时前
🎨 用一次就爱上的图标定制体验:CustomIcons 实战
前端·react.js·icon
谢尔登2 小时前
原来Webpack在大厂中这样进行性能优化!
前端·webpack·性能优化
g***B7382 小时前
JavaScript在Node.js中的模块系统
开发语言·javascript·node.js
Z***25803 小时前
JavaScript在Node.js中的Deno
开发语言·javascript·node.js
cypking3 小时前
Vue 3 + Vite + Router + Pinia + Element Plus + Monorepo + qiankun 构建企业级中后台前端框架
前端·javascript·vue.js
San30.3 小时前
ES6+ 新特性解析:让 JavaScript 开发更优雅高效
开发语言·javascript·es6
Dream it possible!4 小时前
LeetCode 面试经典 150_二叉搜索树_二叉搜索树中第 K 小的元素(86_230_C++_中等)
c++·leetcode·面试