Basic Implementation of AOP Programming in JavaScript

Basic Implementation of AOP Programming in JavaScript

Introduction to AOP

The main function of AOP (Aspect Oriented Programming) is to extract some functions that are not related to the core business logic module. These functions that are not related to business logic usually include log statistics, security control, exception handling, etc. After extracting these functions, they are integrated into the business logic module through "dynamic weaving".

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

While not required, injected code is meant to have cross-cutting concerns, such as adding logging functionality, debugging metadata, or other less general but additional behavior can be injected without affecting the content of the original code.

To give you a good example, suppose you have written your business logic, but now you realize that you didn't add logging code. The usual approach is to centralize the logging logic into a new module and then add logging information function by function.

However, it would certainly be a lot easier if you could get the same logger to be injected with just one line of code at a specific point in the execution of each method you want to log. Isn’t it?

Aspects, advice, and pointcuts (what, when, where)

To make the above definition more formal, let's take the logger as an example to introduce three concepts about AOP. If you decide to explore this paradigm further, these will help you:

  • Aspects (what they are): This is the "aspect" or behavior you want to inject into your target code. In our context (JavaScript), this refers to a function that encapsulates the behavior you want to add.
  • Notify (at what time): When do you want this aspect to be executed? "Advice" specifies some common moments when you want the aspect code to be executed, such as "before", "after", "around", "whenThrowing", etc. In turn, they refer to points in time relative to the execution of the code. For parts that are referenced after code execution, this aspect will intercept the return value and possibly overwrite it if necessary.
  • Pointcuts (where): These refer to the locations in your target code where you want the aspect to be injected. In theory, you can explicitly specify to execute aspect code at any location in the target code. This isn't actually practical, but you could potentially specify, for example: "all methods in my object", or "just this one specific method", or we could even use something like "all methods that start with get_".

With this explanation, you should find it relatively easy to create an AOP-based library to add logging logic to existing OOP-based business logic (for example). All you have to do is replace the existing matching method of the target object with a custom function that adds the aspect logic at the appropriate time and then calls the original method.

Basic Implementation

Since I'm a visual learner, I thought it would be a long shot to show a basic example of how to implement an切面approach to adding AOP-based behavior.

The following examples will illustrate how easy it is to implement and the benefits it brings to your code.

`/** Helper function for getting all methods in 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 instructs */ 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
 } } }

module.exports = { // Main method of export: inject aspects into the target when and where needed 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) 
}) } } }`

Pretty straightforward. As I mentioned, the code above doesn't cover all use cases, but it should be enough to cover the next example.

But before we go any further, take a look at the replaceMethod function. This is where the magic happens. It is able to create new functions and also decide when we call our aspect and how to handle its return value.

Next, I will explain how to use this library:

`const AOP = require("./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)`

This is just a basic object with three methods, nothing special. We want to inject two generic aspects, one for logging incoming properties, and another for analyzing their return values ​​and logging their types. Two aspects, two lines of code (it doesn’t need to be six).

This is the end of the example, and here is the output you will get:

https://camo.githubusercontent.com/f18ef187f4acddab8df097c8aa4521d632e17759bc1c0831a22ada934388d7b5/68747470733a2f2f63646e2d696d616765732d312e6d656469756d2e636f6d2f6d61782f323030302f312a394b5a42774f6262714145754a4176314757537279672e706e67

Advantages of AOP

After knowing the concept and purpose of AOP, you may have guessed why people would want to use aspect-oriented programming, but let's make a quick summary:

  • Great way to encapsulate cross-cutting concerns. I'm a big fan of encapsulation because it means it's easier to read and maintain code that can be reused across your projects.
  • Flexible logic. The logic implemented around advice and pointcuts can give you a lot of flexibility when injecting aspects. This in turn helps you to dynamically turn on and off different aspects of your code logic (pun intended).
  • Reuse aspects across projects. You can think of aspects as components: small, decoupled pieces of code that can run anywhere. If you write your aspects correctly, you can easily share them across different projects.

Main Problems with AOP

Because not everything is perfect, this paradigm has some critics against it.

The main issue they raise is that its main advantage is actually hiding code logic and complexity, which can have side effects when it is not clear.

If you think about it, they have a point, AOP gives you a lot of power to add unrelated behavior to existing methods or even replace their entire logic. Of course, this may not be the exact reason why this paradigm was introduced, and it certainly was not the intention of the examples I provided above.

However, it does allow you to do whatever you want, which combined with a lack of understanding of good programming practices can lead to a very big mess.

In order not to sound too cliché, I will paraphrase Uncle Ben:

With great power comes great responsibility

If you want to use AOP correctly, you must understand the best practices of software development.

In my opinion, just because you can cause a lot of harm using this tool doesn't mean it's a bad tool, because it also brings a lot of benefits (i.e. you can extract a lot of common logic into a centralized location and inject it with a single line of code wherever you need it). To me, this is a powerful tool that is worth learning and definitely worth using.

Aspect-Oriented Programming is a perfect complement to OOP, especially thanks to the dynamic nature of JavaScript, we can implement it very easily (as demonstrated in the code here). It provides powerful capabilities to modularize and decouple large amounts of logic, and even share that logic with other projects later.

Of course, if you don't use it correctly, you can make a real mess. But you can definitely use it to simplify and clean up a lot of code. That's my opinion on AOP, what about you? Have you ever heard of AOP? Have you used it before? Please leave a comment below and share your thoughts!

This is the end of this article about AOP programming in JavaScript. For more relevant js AOP programming content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of AOP implementation in JavaScript (aspect-oriented programming, decorator pattern)
  • JavaScript AOP Programming Example
  • JavaScript AOP Programming Example
  • Javascript AOP (Aspect Oriented Programming) around (surrounding) analysis

<<:  Python virtual environment installation and uninstallation methods and problems encountered

>>:  Detailed explanation of 4 common data sources in Spark SQL

Recommend

Implementation of element shuttle frame performance optimization

Table of contents background Solution New Questio...

Steps for Docker to build its own local image repository

1. Environment and preparation 1. Ubuntu 14.04 2....

Vue+Element UI realizes the encapsulation of drop-down menu

This article example shares the specific code of ...

CSS to achieve fast and cool shaking animation effect

1. Introduction to Animate.css Animate.css is a r...

Sharing some details about MySQL indexes

A few days ago, a colleague asked me a question a...

What knowledge systems do web designers need?

Product designers face complex and large manufactu...

The whole process of configuring hive metadata to MySQL

In the hive installation directory, enter the con...

Basic knowledge of MySQL learning notes

View Database show databases; Create a database c...

The front-end page pop-up mask prohibits page scrolling

A problem that front-end developers often encount...

Correct way to load fonts in Vue.js

Table of contents Declare fonts with font-face co...

Summary of data interaction between Docker container and host

Preface When using Docker in a production environ...

Summary of learning Docker commands in one article

Table of contents Introduction Mirror repository ...

A problem with MySQL 5.5 deployment

MySQL deployment Currently, the company deploys M...