Around (surround) analysis _javascript techniques for Javascript AOP (aspect-oriented programming)

Source: Internet
Author: User
Tags aop closure

AOP is also called aspect-oriented programming, the "notice" is the specific aspect of the implementation, divided into before (forward notice), after (post notice), around (surround notice), with spring students must be very familiar with it, and in JS, AOP is a serious neglected technical points. However, the use of AOP can effectively improve the JS code logic, such as the front-end framework dojo and Yui3 AOP is promoted to a custom event of an intrinsic mechanism, in the source code everywhere. Thanks to this abstraction, Dojo's custom events are unusually powerful and flexible. The implementation of AOP in Dojo in the Dojo/aspect module, there are three main methods: before, after, around, this article will lead us step-by-step to achieve the around method, subsequent articles will be in-depth analysis of the Dojo/aspect module structure system.

JS to implement surround notification, the simplest and most should be thought 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)

Results:

Before function
Foo
After function
Haha, too simple, it is not possible to go back to sleep ....

But, is it a bit too rough .... A good surround .... At least the next call to Obj.foo should also be the result, not a dry "foo"; for this I need to make a change 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 to have the effect of wrapping, but said the name where ....

We also deal with scope issues in the closure that advice returns

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 to be using call to solve the scope problem, let's run a look at:

Horizontal Groove, is this the legendary death cycle ....

It seems that we have to change it, using an intermediate variable to eliminate the dead 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 suddenly became beautiful ....
But does this bunch of code look too low, and we're not going to point to a tall abstraction, 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 is used to decouple the processing process from the concrete object; advice as long as the following format to write, you can achieve around effect

Advice = function (Originalfunc) {return
 function () {
 //before
 originalfunc ();
 After
 }
}

Haha, the moment tall, crazy drag cool off slag days, there are wood ....

  

So here's the question: if you don't take care to call a around method a little too swollen .... The amount of ..... It's a question. Should we let around return a handle with a Remove method that eliminates the binding, just like a bind/remove event.

The remove is to allow the function to not perform the corresponding around method the next time it executes, but only 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 2
before function 1
obj and [object Arguments] After
function 1 after
function 2
   
    obj and undefined
before function 1
   

This one.. Not only the result is a bit messy ... Also reported wrong .... Is can endure, uncle can't endure, uncle can endure, sister-in-law can't endure!

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 () {//When the Remove is invoked, the advised is empty//the advised and previous variables can be accessed in the scope chain of the closure, depending on whether or not the advised is null to call who return Advised?
 Advised.apply (obj, arguments): previous.apply (obj, arguments);
 
 };
 return {remove:function () {////////////////////////////////////////advised
 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);
 The 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 2
before function 1
obj and hello World with
function 1 after
function 2
before funct Ion 2
obj and Hello World's
function 2
obj and Hello World

After the fight, collect the work!

The first time all night to write a blog is also drunk, two o ' clock heard the next door fuck me, four o'clock heard the Crow crows, there is a kind of do not know what birds, JoJo's called, Five o'clock this time a bunch of birds called ....

Reference articles:

Improving JavaScript code with AOP

Yui3 AOP (facet-oriented programming) and OOP (object-oriented programming)

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.