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)