When you think of AOP, you’re bound to think of OOP, or object-oriented programming. AOP and OOP are two design ideas in different business scenarios. This article will try to use vivid and interesting language to introduce the application of AOP in the front-end domain and the difference between AOP and OOP. Before we do that, let’s understand the basic concepts of both.
1. Object-oriented Programming
Everyone has their own understanding of the strict concept of object-oriented programming, and I won’t read it again here. But we can use an analogy from our own lives to prepare for the rest of this article:
There was this girl who had to pay her phone bill at the end of every month. Every time she charged her phone, she had to open Alipay, fill in her phone number, select the amount to be charged, and then click the recharge button to complete the charge. The whole process, we can call it process oriented recharge.
Then she found a boyfriend, and the burden fell on him to charge the phone. So the girl each time before recharge, will recharge the amount to her boyfriend, he finished the operation to tell her recharge. The whole process can be called object-oriented recharge. Because girls only need to care about the amount of recharge and recharge results, do not care about the specific how recharge.
2. Aspect Oriented Programming (AOP)
Object-oriented programming seems to have been able to meet most scenarios, can be extended and reused, but what problem is aspect programming to solve? Based on the recharge example above, let’s expand the scenario:
After a while, the girl found that her boyfriend could only use Alipay to top up the phone bill. One day, she wanted her boyfriend to use wechat to top up the phone bill, but found that wechat and Alipay could not be installed on mobile phones in the market at the same time. The girl had to find a boyfriend who had wechat on his phone. But having two boyfriends at the same time is exhausting. What should a girl do?
The face-to-face recharge offered a solution: the girl bought two extra phones, one with wechat and the other with Alipay, and then dumped one of her boyfriends. So every time she wants her boyfriend to help charge the phone bill, she can give him one of the two phones and use wechat or Alipay, the girl can decide.
At this point, I’m sure you have an outline in your mind of the difference between AOP and OOP. What exactly is AOP defined? It is a technique for unified maintenance of logic functions through precompilation or runtime dynamic proxies. OOP is the encapsulation of object properties and behaviors, while AOP is the encapsulation of steps and phases. The “boyfriend” in the above example is the encapsulation of objects, and the “recharge method (Alipay/wechat)” is the logical fragment of the “recharge” behavior. AOP is a further enhancement of OOP, so to speak.
AOP has three main concepts:
1. Aspect
This is where the AOP initial A comes from, aspect = pointcut + advice.
2. Pointcut
A pointcut is a class or method that is specifically enhanced.
3. Advice
Enhanced processing at pointcut execution, such as callback functions, such as Dojo’s After methods, described below, are advice.
Let’s write a piece of code to get a feel for these three abstractions. Suppose we have an object that contains a print method:
let TestObj = {
log: (a)= > {
console.log('print log'); }}Copy the code
We would like to add a function that tells us before printing that we are ready to print and after printing that we are finished executing, but we can’t change the code inside the object. Then we can write a new method:
let emitter = (target) {
console.log('About to start printing');
target.log();
console.log('End of print');
}
emitter(TestObj);
Copy the code
The code above is the simplest and most typical way to implement AOP. The Emitter function does not change the logic of the original object, but “wraps” and “enhances” it. Log methods are commonly called pointcuts, while console.log is called a notice, emitter is called a slice, and TestObj is called a slice.
3. Why does front-end need AOP
There is a lot of use of AOP in the Spring framework, but it is not front end and we won’t discuss it. The Front-end Dojo framework represents an early use of AOP ideas at the bottom, providing aspect modules internally. The aspect module provides three methods:
after
before
around
The names of the three methods give you a pretty good idea of what they are for. For example, before is used to do the final processing of the parameters before sending the request, after is used to process the data returned by Ajax, and around is used during the request. All three methods do not change the logic of the core code, but simply “wrap” it, much like the JS prefix and callback functions. When it comes to modern front-end development, we often encounter and use forms. Of course, we will encapsulate the various business forms as business form components, as this is a great way to reduce the development effort.
One day, however, the product manager required that each business form component be submitted with a buried spot. We decided to add buried logic to each business component, but the buried logic was the same, copy-and-paste. Is there any way to reuse buried logic? With OOP in mind, we consider abstracting buried point logic into a single Log class that can be invoked within a business component. But as a side effect, logs are coupled to business components, and every time the Log class changes, the behavior of all business components’ burial points changes, which is another headache. So we need a new way of coding that can dynamically inject log-burying logic into a given component or even into a given method. The solution is the same as the code in the example above, which is AOP.
4. AOP in the front-end domain
1.javascript
Since AOP is not a front-end source concept, prior to the release of ES6, abstract emulation was only possible using native JS, and a common solution was to prototype Function, which was prone to bugs. Javascript was introduced as an official standard with the release of ES6 decorators. The standard is borrowed from other object-oriented languages, making it more formal to write code with AOP ideas for front-end development. Like Python, JS uses the @ keyword. Let’s see how it works:
@decorator
class TestClass {
// ...
}
function decotator(targetClass) {
targetClass.rejectDecorator = true;
}
TestClass.rejectDecorator // true
Copy the code
As you can see from the above code, the decorator modifies variables inside the component, and the decorator is essentially a function. Since it is a function, it must be possible to control the behavior of decorators by passing in arguments:
function proDecorator(boolValue) {
return function(targetClass) {
target.rejectDecorator = boolValue;
}
}
@proDecorator(true)
class TestClass(a){}
TestClass.rejectDecorator // true
@proDecorator(false)
class TestClass(a){}
TestClass.rejectDecorator // false
Copy the code
Decorators can decorate not only classes but also methods within classes. The Log problem we mentioned above can be solved by using decorators to decorate internal methods:
class TestClass {
@log
add(a, b) {
returna + b; }}function log(target, name, descriptor){
let oldValue = descriptor.value;
descriptor.value = function() {
console.log(`Calling ${name} with`.arguments);
return oldValue.apply(this.arguments);
};
return descriptor;
}
const Test = new TestClass();
const num = Test.add(2.4);
console.log(num);
// calling add with [object Arguments] { ... }
/ / 6
Copy the code
There are many decorative methods, interested readers can consult, this article is no longer described. From the above code, we found that the decorator is a good implementation of the design philosophy advocated by AOP, while being parameterized itself, free of the limitations of traditional functional tools.
2.React
Readers familiar with React will have heard of mixins, which are a way to organize functions inside React. Facebook has since moved away from this model, recommending that developers use HOC. In fact, HOC is a typical way of coding under the guidance of AOP. Let’s look at the following code:
//WrappedComponent is the processed component
function HOC(WrappedComponent){
return class HOC extends Component {
render(){
const newProps = {type:'HOC'};
return <div>
<WrappedComponent {. this.props} {. newProps} / >
</div>
}
}
}
@HOC
class OriginComponent extends Component {
render(){
return <div>This is the original component</div>
}
}
//const newComponent = HOC(OriginComponent)
Copy the code
newProps
render
props
@HOC
props
5. To summarize
AOP and OOP are not contradictory in themselves. In software development, we can divide the code structure vertically based on OOP, and inject logical units horizontally based on AOP, so as to make the software structure more three-dimensional. The robustness of software engineering can only be improved by complementing each other.