AoP
~~~~~mm, Baidu Encyclopedia once~~~
AOP is the abbreviation of Aspect Oriented Programming, which means: facet-oriented programming, a technology for unified maintenance of program functions through precompilation and run-time dynamic agents.AOP is the continuation of OOP, a hot spot in software development, an important content in Spring framework, and a derived paradigm of functional programming.With AOP, parts of business logic can be isolated, which reduces the coupling between parts of business logic, improves the reusability of programs, and improves the efficiency of development.
- As a front-end, Xiao Meng understood that it was to separate other businesses from the main process and then cut in from the side.No intrusive modifications to the original function.
Say nothing but a classic online example:
Business logic:
Main Business: Modify Database
Start point 1: Print logs before modification
Start Point 2: Print Log After Modification
Function.prototype.before = function(beforeFunc) { let that = this return function() { beforeFunc.apply(this, arguments) return that.apply(this, arguments) } } Function.prototype.after = function(afterFunc) { let that = this return function() { let ret = that.apply(this, arguments) afterFunc.apply(this, arguments) return ret } } function updateDb() { console.log(`update db`) } function beforeUpdateDb() { console.log(`before update db`) } function afterUpdateDb() { console.log(`updated db`) } updateDb = updateDb.before(beforeUpdateDb).after(afterUpdateDb) updateDb()
Principle: Actually, it wraps the main business updateDb twice and returns a new method.The new method calls the cut-in method before and after the original method call, avoiding direct changes on the main method.
- Is this poor readability and code maintainability? Here's how you can program facets with an ornament.
Decorator decorator
- Decorators are incompatible with ES7 modern tourists and require babel translation, plugin-transform-decorators-legacy
- Decorators can only work on the class itself, its methods or properties, and its access operators
- Modifier'@'is an identifier
1 Pair of Class Decorations
@create class Apes { } // Modify the class itself function create(className) { className.prototype.create = function() { console.log('Manufacturing Tools') } return descriptor } let apes1 = new Apes() apes1.create() // Manufacturing Tools
- Modify the class itself: create(className).Decorators are essentially compile-time functions.
- To modify subclasses, modify the subclasses by using className.prototype.
2 Method Modifications on Classes
class Apes { @eatMore eat() { console.log('eat fruit') } } // Modification Method function eatMore(className, propName, descriptor) { //console.log(descriptor) let value = descriptor.value descriptor.value = function() { console.log('Dirt-poor') value() } return descriptor } let apes1 = new Apes() apes1.eat()
- Decorate eatMore(className, propName, descriptor) on a class's methods
className - Modified class propName - Modified property name descriptor - Description object for this property
Object.defineProperty dependent on ES5 as seen from the descriptor attribute descriptor
Review Object.defineProperty
Value: The value of the property, defaulting to undefined writable: Whether the value of the property can be modified, default value is true enumerable: Can properties be returned through a for-in loop?Default to true configurable: Whether attributes can be redefined by deleting them, whether attributes can be modified, whether attributes can be modified to accessor attributes, default to true.
- The above method modifications to classes actually take their methods through descriptor.value and wrap them back
- You can also directly modify other properties on the descriptor or return a new descriptor
3. Decoration for access operators
class test { //@nonenumerable get kidCount() { return 111 } } function disWirte(target, name, descriptor) { descriptor.writable = false return descriptor } let p = new test() console.log(p.kidCount) p.kidCount = 222n descriptor; // throw // TypeError: Cannot set property kidCount of #<Person> which has only a getter
4. Modifying Passwords
class Apes { @say('Can say Chinese') say() { console.log('Grilla Bonobo Grilla') } } // Modify method and pass parameters function say(str) { return function(className, propName, descriptor) { descriptor.value = function() { console.log(str) } return descriptor } }
- Passing parameters by Curitization
application
1. Applying to the calculation of Fibonacci series
const memory = () => { const cache = {} //Cache pool return (target, name, descriptor) => { // Original method const method = descriptor.value // Packaging method descriptor.value = function(key) { if (cache[key]) { return cache[key] } const ret = method.apply(target, [key]) cache[key] = ret return ret } return descriptor } } let count = 0 class Test { @memory() fb(n) { count++ if (n === 1) return 1 if (n === 2) return 1 return this.fb(n - 1) + this.fb(n - 2) } } const t = new Test() console.log(t.fb(10)) console.log(count)
2. Type checking on access operator-set
class test { constructor() { this.a = 1 } get a() { return this.a } @check('number') set a(v) { return v } } function check(type) { return function(target, prop, descriptor) { let v = descriptor.value return { enumerable: true, configurable: true, get: function() { return v }, set: function(c) { var curType = typeCheck(c) if (curType !== type) { throw `${prop}Must be ${type}type` } v = c } } } } function typeCheck(c) { if (c === undefined) { return undefined } if (c === null) { return null } let type = typeof c if (type === 'object') { return c.constructor == Array ? 'array' : 'object' } return type } let t = new test(11) t.a = 2 console.log(t.a) // 2 t.a = [] console.log(t.a) // throw a must be of type number