Javascriptaop (Aspect-Oriented Programming) around (WRAP) analysis _ javascript skills

Source: Internet
Author: User
This article mainly introduces the round of Javascriptaop (cross-section programming). If you need it, you can refer to Aop, which is also called cross-section programming. the "notification" is the specific implementation of the cross-section, it can be divided into before (pre-notification), after (post-notification), and around (surround notification). those who have used spring must be very familiar with it, but in js, AOP is a technical point that has been seriously ignored. However, aop can effectively improve the js code logic. for example, AOP in the front-end framework dojo and yui3 is promoted to an internal mechanism of custom events, which can be seen everywhere in the source code. Thanks to this abstraction, the custom events of dojo are exceptionally powerful and flexible. In the dojo/aspect module, the implementation of aop mainly includes three methods: before, after, and around. This article will guide you to implement the around method step by step, the structure of the dojo/aspect module will be further analyzed in subsequent articles.

To implement surround notification in js, the simplest and most important thing to think of is to use callback (callback)

advice = function(originalFunc){ console.log("before function"); originalFunc(); console.log("after function");}var obj = { foo: function(){ console.log('foo'); }}advice(obj.foo)

Result:

Before function
Foo
After function
Haha, it's too simple. can I go back to bed ....

But isn't it a little rough .... Let's talk about it .... At least the next call of obj. foo should also be the result, rather than a dry "foo". For this reason, we need to modify it and use the closure.

advice = function(originalFunc){ return function() { console.log("before function"); originalFunc(); console.log("after function"); }}var obj = { foo: function(){ console.log(this.name); }, name: "obj"}obj.foo = advice(obj.foo)obj.foo()

Output:

Before function

After function

It seems that the effect of the circle has been reached, but the name that says yes goes ....

In the closure returned by advice, we also need to handle the scope issue.

advice = function(originalFunc){ return function() { console.log("before function"); originalFunc(); console.log("after function"); }}var obj = { foo: function(){ console.log(this.name); }, name: "obj"}keepContext = function() { return obj['foo'].call(obj);}obj.foo = advice(keepContext);

It seems that call is used to solve the scope problem. let's take a look at it:

Slot, isn't this the legendary endless loop ....

It seems that we still need to change it. we need to use an intermediate variable to eliminate the endless loop.

advice = function(originalFunc){ return function() { console.log("before function"); originalFunc(); console.log("after function"); }}var obj = { foo: function(){ console.log(this.name); }, name: "obj"}var exist = obj.foo;keepContext = function() { return exist.call(obj);}obj.foo = advice(keepContext);obj.foo();

Output:

Before function
Obj
After function

Haha, the world has suddenly become better ....
But does this pile of code look too low? do we want to abstract it on the tall? well, I think so too.

function around(obj, prop, advice){ var exist = obj[prop]; var advised = advice(function(){ return exist.call(obj, arguments); }); obj[prop] = advised;}advice = function(originalFunc){ return function() { console.log("before function"); originalFunc(); console.log("after function"); }}var obj = { foo: function(){ console.log(this.name); }, name: "obj"}around(obj, 'foo', advice);obj.foo();

The around method decouples the processing process from the specific object. advice can achieve the around effect as long as it is written in the following format:

advice = function(originalFunc){ return function() { //before originalFunc(); //after }}

Haha, I am so tall that I am so arrogant and cool that I can't help myself ....

  

The problem arises: if you accidentally call the around method once again, it will be swollen .... Amount .... This is a problem. Should we let round return a handle, which has a remove method to eliminate binding, just like binding/removing events.

To remove a function, you do not need to execute the corresponding round method the next time you execute the function. Instead, you only need to run the originalFunc method.

function around(obj, prop, advice){ var exist = obj[prop]; var previous = function(){ return exist.call(obj, arguments); }; var advised = advice(previous); obj[prop] = advised;  return { remove: function(){ obj[prop] = exist; advice = null; previous = null; exist = null; obj = null; } }}var count = 1;advice = function(originalFunc){ var current = count++; return function() { console.log("before function " + current); originalFunc(arguments); console.log("after function " + current); }}var obj = { foo: function(arg){ console.log(this.name + " and " + arg); }, name: "obj"}h1 = around(obj, 'foo', advice);h2 = around(obj, 'foo', advice);obj.foo();h1.remove();obj.foo();h2.remove();obj.foo();

Output:

before function 2before function 1obj and [object Arguments]after function 1after function 2obj and undefinedbefore function 1

This .. Not only is the result a little messy... An error is also reported .... It's tolerable. it's intolerable!

Ah, closure... Please give me strength!

Function around (obj, prop, advice) {var exist = obj [prop]; var previous = function () {return exist. apply (obj, arguments) ;}; var advised = advice (previous); obj [prop] = function () {// after removing is called, advised is empty // The advised and previous variables can be accessed in the scope chain using the closure. based on whether advised is empty, the caller can return advised? Advised. apply (obj, arguments): previous. apply (obj, arguments) ;}; return {remove: function () {// use the scope chain of the closure to leave advised empty when removing, in this way, the following items cannot be deleted during the execution: // obj [prop] = exist; advised = null; advice = null; // previous = null; // exist = null; // obj = null ;}} var count = 1; advice = function (originalFunc) {var current = count ++; return function () {console. log ("before function" + current); originalFunc. apply (this, arguments); console. log ("after function" + current);} var obj = {foo: function (arg) {console. log (this. name + "and" + arg) ;}, name: "obj"} h1 = around (obj, 'foo', advice); h2 = around (obj, 'foo ', advice); obj. foo ('Hello World'); h1.remove (); obj. foo ('Hello World'); h2.remove (); obj. foo ('Hello World ');

Output:

before function 2before function 1obj and hello worldafter function 1after function 2before function 2obj and hello worldafter function 2obj and hello world

After finishing the fight, do it!

The first time I wrote a blog all night, I was drunk. at two o'clock, I heard fuck me next door. at four o'clock, I heard the Crow scream. There was another kind of unknown birds. at five o'clock, a bunch of birds were called ....

References:

Use AOP to improve javascript code

AOP and OOP of yui3)

Understanding of aspect-oriented programming (AOP)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.