preface

We all know about object-oriented programming, and in the JavaScript world, we hear about functional programming at least maybe a lot, but have you heard about aspect programming before?

Just like OOP and FP in JavaScript, you can easily mix AOP with FP or OOP. Let’s take a look at what AOP is all about and what it can do for JavaScript developers.

The body of the

1. Programming paradigm

Programming paradigm (programming thought), generally a typical programming style. Common programming paradisms are: functional programming, instruction programming, procedural programming, object-oriented programming and so on.

Programming paradises provide and determine the programmer’s view of program execution. For example, in object-oriented programming, programs are generally considered to be a series of interacting objects. Due to methodological differences, object-oriented programming paradogs can be divided into class-based programming and prototype-based programming, while in functional programming a program is considered to be a sequence of stateless function calculations.

2. AOP

Aspect-oriented programming (AOP) is a programming idea in computer science, which aims to further separate crosscutting concerns from business entities to improve the modularity of program code. The idea of section-oriented programming is also the foundation of section-oriented software development. The concept of sections stems from a fusion of object-oriented programming and computational reflection, but it is not limited to that. It can also be used to improve traditional functions. Other programming concepts related to aspects include meta-object protocols, subjects, mixins, and delegates.

Section-oriented programming gives us a way to inject code into existing functions or objects without modifying the target logic.

Injected code is not required, but where there are crosscutting concerns, such as adding logging capabilities, debugging metadata, performance statistics, security controls, transaction handling, exception handling, or less general functionality, additional behavior can be injected without affecting the original code. Pull them out and embed them in the business logic with “dynamic” inserts. Business modules can be relatively clean and unpolluted, while these function points can be reused and decoupled from modules.

As a good example, suppose you had written your business logic, but now you realize that you have no logging code. The normal way to do this is to centralize the logging logic in a new module and function through functions that add logging information.

To formalize some of the above definitions, three AOP concepts are generally covered:

  1. Aspects (What) section
  2. Advice (s)
  3. Pointcut tangent point (Where)

3. Simple implementation of AOP

A basic example might help you understand how to implement an AOP based injection method to add behavior.


/** Helping function used to get all methods of an object */

const getMethods = (obj) = > Object.getOwnPropertyNames(Object.getPrototypeOf(obj)).filter(item= > typeof obj[item] === 'function')

/** Replace the original method with a custom function that will call our aspect when the advice dictates */

function replaceMethod(target, methodName, aspect, advice) {
    const originalCode = target[methodName]
    target[methodName] = (. args) = > {
        if(["before"."around"].includes(advice)) {
            aspect.apply(target, args)
        }
        const returnedValue = originalCode.apply(target, args)
        if(["after"."around"].includes(advice)) {
            aspect.apply(target, args)
        }
        if("afterReturning" == advice) {
            return aspect.apply(target, [returnedValue])
        } else {
            return returnedValue
        }
    }
}

  // Main method exported: inject the aspect on our target when and where we need to
  
export const inject = function(target, aspect, advice, pointcut, method = null) {
        if(pointcut == "method") {
            if(method ! =null) {
                replaceMethod(target, method, aspect, advice)    
            } else {
                throw new Error("Tryin to add an aspect to a method, but no method specified")}}if(pointcut == "methods") {
            const methods = getMethods(target)
            methods.forEach( m= > {
                replaceMethod(target, m, aspect, advice)
            })
        }
    }
}
Copy the code

Notice the replaceMethod function, which is where all the magic happens. This is where the new function is created and where we decide when to call the aspect and what to do with its return value.

import AOP from "./aop.js"

class MyBussinessLogic {

    add(a, b) {
        console.log("Calling add")
        return a + b
    }

    concat(a, b) {
        console.log("Calling concat")
        return a + b
    }

    power(a, b) {
        console.log("Calling power")
        return a ** b
    }
}

const o = new MyBussinessLogic()

function loggingAspect(. args) {
    console.log("== Calling the logger function ==")
    console.log("Arguments received: " + args)
}

function printTypeOfReturnedValueAspect(value) {
    console.log("Returned type: " + typeof value)
}

AOP.inject(o, loggingAspect, "before"."methods")
AOP.inject(o, printTypeOfReturnedValueAspect, "afterReturning"."methods")

o.add(2.2)
o.concat("hello"."goodbye")
o.power(2.3)
Copy the code

Note: Be careful to use AOP in JS! Because some JS methods are asynchronous.

Use async/await/Promise if necessary to ensure sequential code execution.

4. Benefits of AOP

  1. Encapsulate crosscutting concerns

This means that you can more easily read and maintain code that is reused throughout the project.

  1. Flexible logic

The logic implemented around pointcuts gives you a lot of flexibility when injecting aspects. This, in turn, helps with dynamic open and close logic.

  1. Reuse across projects

You can think of sections as components that can run small, decoupled pieces of code anywhere. If you write aspects correctly, you can easily share them across different projects.

5. More

In the pure front-end domain, we often see AOP ideas.

  1. Vue. Js data binding principle
Application of setter/getter in Object.defineProperties() or ProxyCopy the code
  1. Hooks design ideas in major front-end frameworks
New Vue ({beforeUpdate () {} / / insert the logic, the updated () {} / / insert the logic,... })Copy the code

conclusion

Not everything is perfect, and some oppose this paradigm. The main problem with it is that it actually has the benefit of hiding logic and complexity, but it can also cause side effects when this is not quite clear.

Section-oriented programming AOP is a perfect complement to OOP, especially because of the dynamic nature of JavaScript, which can be easily implemented. It provides great functionality to modularize and decouple a lot of logic that you can even share with other projects.