Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >在Javascript中进行面向切面编程

在Javascript中进行面向切面编程

原创
作者头像
挥刀北上
发布于 2023-07-20 02:59:52
发布于 2023-07-20 02:59:52
46300
代码可运行
举报
文章被收录于专栏:Node.js开发Node.js开发
运行总次数:0
代码可运行

什么是面向切面编程?

面向切面编程(Aspect-oriented programming,AOP)是一种编程范式。做后端 Java web 的同学,特别是用过 Spring 的同学肯定对它非常熟悉。AOP 是 Spring 框架里面其中一个重要概念。可是在 Javascript 中,AOP 是一个经常被忽视的技术点。

场景

假设你现在有一个牛逼的日历弹窗,有一天,老板让你统计一下每天这个弹窗里面某个按钮的点击数,于是你在弹窗里做了埋点;

过了一个星期,老板说用户反馈这个弹窗好慢,各种卡顿。你想看一下某个函数的平均执行时间,于是你又在弹窗里加上了性能统计代码。

时间久了,你会发现你的业务逻辑里包含了大量的和业务无关的东西,即使是一些你已经封装过的函数。

那么 AOP 就是为了解决这类问题而存在的。

关注点分离

分离业务代码和数据统计代码(非业务代码),无论在什么语言中,都是AOP的经典应用之一。从核心关注点中分离出横切关注点,是 AOP 的核心概念。

在前端的常见需求中,有以下一些业务可以使用 AOP 将其从核心关注点中分离出来 - Node.js 日志log - 埋点、数据上报 - 性能分析、统计函数执行时间 - 给ajax请求动态添加参数、动态改变函数参数 - 分离表单请求和验证 - 防抖与节流

装饰器(Decorator)

提到 AOP 就要说到装饰器模式,AOP 经常会和装饰器模式混为一谈。

在ES6之前,要使用装饰器模式,通常通过Function.prototype.before做前置装饰,和Function.prototype.after做后置装饰(见《Javascript设计模式和开发实践》)。

Javascript 引入的 Decorator ,和 Java 的注解在语法上很类似,不过在语义上没有一丁点关系。Decorator 提案提供了对 Javascript 的类和类里的方法进行装饰的能力。(尽管只是在编译时运行的函数语法糖)

埋点数据上报

因为在使用 React 的实际开发中有大量基于 Class 的 Component,所以我这里用 React 来举例。

比如现在页面中有一个button,点击这个button会弹出一个弹窗,与此同时要进行数据上报,来统计有多少用户点击了这个登录button。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React, { Component } from 'react';
import send from './send';

class Dialog extends Component {

    constructor(props) {
        super(props);
    }

    @send
    showDialog(content) {
        // do things
    }

    render() {
        return (
            <button onClick={() => this.showDialog('show dialog')}>showDialog</button>
        )
    }
}

export default Dialog;

上面代码引用了@send装饰器,他会修改这个 Class 上的原型方法,下面是@send装饰器的实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export default function send(target, name, descriptor) {
    let oldValue = descriptor.value;

    descriptor.value = function () {
        console.log(`before calling ${name} with`, arguments);
        return oldValue.apply(this, arguments);
    };

    return descriptor;
}

在按钮点击后执行showDialog前,可以执行我们想要的切面操作,我们可以将埋点,数据上报相关代码封装在这个装饰器里面来实现 AOP。

前置装饰和后置装饰

上面的send这个装饰器其实是一个前置装饰器,我们可以将它再封装一下使它可以前置执行任意函数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function before(beforeFn = function () { }) {
    return function (target, name, descriptor) {
        let oldValue = descriptor.value;

        descriptor.value = function () {
            beforeFn.apply(this, arguments);
            return oldValue.apply(this, arguments);
        };

        return descriptor;
    }
}

这样我们就可以使用@before装饰器在一个原型方法前切入任意的非业务代码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function beforeLog() {
    console.log(`before calling ${name} with`, arguments);
}
class Dialog {
    ...
    @before(beforeLog)
    showDialog(content) {
        // do things
    }
    ...
}

@before装饰器类似,可以实现一个@after后置装饰器,只是函数的执行顺序不一样。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function after(afterFn = function () { }) {
    return function (target, name, descriptor) {
        let oldValue = descriptor.value;

        descriptor.value = function () {
            let ret = oldValue.apply(this, arguments);
            afterFn.apply(this, arguments);
            return ret;
        };

        return descriptor;
    }
}

性能分析

有时候我们想统计一段代码在用户侧的执行时间,但是又不想将打点代码嵌入到业务代码中,同样可以利用装饰器来做 AOP。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function measure(target, name, descriptor) {
    let oldValue = descriptor.value;

    descriptor.value = function () {
        let ret = oldValue.apply(this, arguments);
        performance.mark("startWork");
        afterFn.apply(this, arguments);
        performance.mark("endWork");
        performance.measure("work", "startWork", "endWork");
        performance
          .getEntries()
          .map(entry => JSON.stringify(entry, null, 2))
          .forEach(json => console.log(json));
        return ret;
    };

    return descriptor;
}

在要统计执行时间的类方法前面加上@measure就行了,这样做性能统计的代码就不会侵入到业务代码中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Dialog {
    ...
    @measure
    showDialog(content) {
        // do things
    }
    ...
}

小结

面向切面编程的重点就是将核心关注面分离出横切关注面,前端可以用 AOP 优雅的来组织数据上报、性能分析、统计函数的执行时间、动态改变函数参数、插件式的表单验证等代码。

http://www.alloyteam.com/2013/08/yong-aop-gai-shan-javascript-dai-ma/

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
javascript设计模式十:装饰者模式
在js函数开发中,想要为现有函数添加与现有功能无关的新功能时,按普通思路肯定是在现有函数中添加新功能的代码。这并不能说错,但因为函数中的这两块代码其实并无关联,后期维护成本会明显增大,也会造成函数臃肿。
前端_AWhile
2019/08/29
4560
基于装饰器——我劝你不要在业务代码上装逼!!!
沉浸式趣谈
2024/03/13
1350
基于装饰器——我劝你不要在业务代码上装逼!!!
JavaScript设计模式--装饰者模式
有时我们不希望某个类天生就非常庞大,一次性包含许多职责。那么我们就可以使用装饰着模式。 装饰着模式可以动态地给某个对象添加一些额外的职责,从而不影响这个类中派生的其他对象。 装饰着模式将一个对象嵌入另一个对象之中,实际上相当于这个对象被另一个对象包装起来,形成一条包装链。
奋飛
2019/08/15
4290
设计模式(11)[JS版]-JavaScript中的注解之装饰器模式
装饰器模式模式动态地扩展了(装饰)一个对象的行为,同时又不改变其结构。在运行时添加新的行为的能力是由一个装饰器对象来完成的,它 "包裹 "了原始对象,用来提供额外的功能。多个装饰器可以添加或覆盖原始对象的功能。装饰器模式属于结构型模式。和适配器模式不同的是,适配器模式是原有的对象不能用了,而装饰器模式是原来的对象还能用,在不改变原有对象结构和功能的前提下,为对象添加新功能。
AlbertYang
2020/09/08
9070
设计模式(11)[JS版]-JavaScript中的注解之装饰器模式
JavaScript设计模式之装饰器模式
手机壳就是装饰器,没有它手机也能正常使用,原有的功能不变,手机壳可以减轻手机滑落的损耗。
FinGet
2019/06/28
4750
在JS中统计函数执行次数与执行时间
不过在Chrome中内置了一个 console.count 方法,可以统计一个字符串输出的次数。我们可以利用这个来间接地统计函数的执行次数
书童小二
2018/10/09
3.9K0
Thinking--AOP思想在前端中的应用
AOP(Aspect Oriented Programming),面向切面编程。其从主关注点中分离出横切关注点是面向侧面的程序设计的核心概念。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来。
奋飛
2019/08/14
4220
JS函数hook
我在阅读《JavaScript 设计模式与开发实践》的第 15 章 装饰者模式,突然发现 JS 逆向中 hook 函数和 js 中的装饰者模式有点像,仔细阅读完全篇后更是对装饰器与 hook 有了更深的理解于是便有了这篇文章来记录一下该操作。
愧怍
2022/12/27
4K0
介绍几个JavaScript设计模式及场景应用
当然我们可以用一个通俗的说法:设计模式是解决某个特定场景下对某种问题的解决方案。因此,当我们遇到合适的场景时,我们可能会条件反射一样自然而然想到符合这种场景的设计模式。
winty
2020/04/14
7580
JavaScript高阶函数
把一些跟核心业务逻辑模块无关的功能抽离出来,这些跟业务逻辑无关的功能通常包括日志统计、安全控制、异常处理等 可以保持业务逻辑模块的纯净和高内聚性
薛定喵君
2019/11/06
4860
JS设计模式--装饰者模式
所谓装饰者模式,就是动态的给类或对象增加职责的设计模式。它能在不改变类或对象自身的基础上,在程序的运行期间动态的添加职责。这种设计模式非常符合敏捷开发的设计思想:先提炼出产品的MVP(Minimum Viable Product,最小可用产品),再通过快速迭代的方式添加功能。
Dickensl
2022/06/14
1.2K0
Javascript 装饰器极速指南
Decorators 是ES7中添加的JavaScript新特性。熟悉Typescript的同学应该更早的接触到这个特性,TypeScript早些时候已经支持Decorators的使用,而且提供了ES5的支持。本文会对Decorators做详细的讲解,相信你会体验到它给编程带来便利和优雅。 我在专职做前端开发之前, 是一名专业的.NET程序员,对.NET中的“特性”使用非常熟悉。在类、方法或者属性上写上一个中括号,中括号里面初始化一个特性,就会对类,方法或者属性的行为产生影响。这在AOP编程,以及ORM
用户1631416
2018/04/12
9630
Javascript 装饰器极速指南
AOP --- 面向切面编程
「AOP(Aspect-Oriented Programming)」 编程思想是一种面向切面编程的编程范式。在日常的软件开发中,我们经常会遇到一些「横切关注点(cross-cutting concerns)」,如日志记录、事务处理、权限控制、异常处理等。这些横切关注点可能会存在于程序的多个模块中,使得程序的不同模块之间存在较强的耦合性,从而影响了程序的可维护性和可扩展性。AOP编程思想的目的就是将这些横切关注点从程序的业务逻辑中剥离出来,并将其模块化处理,从而提高程序的可维护性和可扩展性。
Niuery Diary
2023/10/22
3250
AOP --- 面向切面编程
JavaScript设计模式与开发实践 - 高阶函数的应用
定义 高阶函数是指至少满足下列条件之一的函数: 函数可以作为参数被传递; 函数可以作为返回值输出。 JavaScript语言中的函数显然满足高阶函数的条件,在实际开发中,无论是将函数当作参数传递,还是让函数的执行结果返回另外一个函数,这两种情形都有很多应用场景,以下就是一些高阶函数的应用。 应用 作为参数传递 ajax异步请求 // callback为待传入的回调函数 var getUserInfo = function(userId, callback) { $.ajax("http://xxx
laixiangran
2018/04/11
9310
面向切面编程
面向切面编程(Aspect Oriented Programming),简称AOP。作为面向对象编程的一个强力补充,在业务系统中很少被关注,却随着Spring的出现而名声鹊起。
李鸿坤
2020/07/18
1.2K0
面向切面编程
python 中面向切面编程AOP和装饰器
简言之、这种在运行时,编译时,类和方法加载时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
Tim在路上
2020/08/04
8460
面向切面编程
面向切面编程(Aspect Oriented Program, 简称 AOP)是一种编程范式,用于解藕系统中的横切关注点。
Jimmy_is_jimmy
2023/07/31
2610
面向切面编程
什么是AOP面向切面编程?怎么简单理解?
面向切面编程(AOP)通过将横切关注点(cross-cutting concerns)分离出来,提供了一种增强代码模块化和可维护性的方法。
张飞的猪
2024/11/06
1580
什么是AOP面向切面编程?怎么简单理解?
面向切面编程
在传统的编写业务逻辑处理代码时,我们一般会习惯性地做几件事情:日志记录、事务控制及权限控制等,然后才是编写核心的业务逻辑处理代码。当代码编写完毕回头再看时,不禁发现。扬扬洒洒上百行代码中。真正用于核心业务逻辑处理才那么几行。如图6-4所看到的。
狼啸风云
2020/01/14
6330
面向切面编程
spring之AOP(面向切面编程)
本博客将深入探讨面向切面编程(AOP)的概念以及在Spring框架中的应用。我们将讨论如何创建切面和通知,探究切面与代理模式的关系。通过代码示例和注释,详细介绍上述内容,同时提供注意事项和总结,以便更好地理解和应用AOP。
默 语
2024/11/20
1500
spring之AOP(面向切面编程)
相关推荐
javascript设计模式十:装饰者模式
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验