For a long time I use decorators in JavaScript. Recently I saw a
habrotopic about impurities, which prompted me to share my own experience, because the technologies are a bit similar.
What does not suit me in known implementations?
The implementations suggested by the first links in Google do not work the way it does in Python. In many articles, it is proposed to create an object, fill its fields with functions, and make calls decoded through these fields.
The first page has several links that use methods similar to mine,
There are many more implementations, but they are not interesting to me.
I will tell the most correct from my point of view.
Normal decorator
So what is a decorator?
A decorator is a function that adds functionality to the function's argument.
Python example:
def superfunc(n=2): print("Megclosure created") def clos(func): print("Megclosure used") def clos1(*args, **kwargs): print("Megclosured function",func.__name__) res = func(*args, **kwargs) return (res**n) return clos1 return clos def a(par): return par+9; b = (superfunc())(a) @superfunc(3) def c(txt): return len(txt)+1 print ( b(1),c("abc"*3))
What are we doing here?
We here create a function that creates another function that performs what we need and calls the function being decorated.
')
How will it be on javascript
So, we want to call a function, passing it a function and, possibly, additional parameters, and get the decoded function b, i.e.
function decorator(){ ..... } ..... function a(){ ...... } ...... var b=decorator(a, arg1, arg2,....., argN);
.
I will give a piece of code from one of its
libraries function withVars(f, variables) { var args = Array.prototype.slice.call(arguments, 1);
And application:
function a(){ var str =""; for(var i=0;i<arguments.length;i++){ str+=arguments[i]+" "; } alert(str); } a(1,2,4,5,"six");
As a result, in several lines of code we get a powerful effect.
With a slight movement of the hand, the function can be remade so that the parameter is added to the beginning. To do this, simply replace
Array.prototype.push.apply(p, args); f.apply(this, p);
on
Array.prototype.push.apply(args,p); f.apply(this, args);
.
Possible uses
- Suppose you need to call callback2 from callback1, callback3 from callback2, etc., and at the same time transfer some data from one callback to another. We cannot transfer additional information in the event source object. For example, when we use GM_xmlhttpRequest. In short, the source of the events is hidden from us, and a function sticks out that we can call, but which does not store arbitrary information for transmission to the callback. There will be many events and they will occur "in parallel", so creating a variable is not an option.
Then we do this:
function cb1(evt){ ....... GM_xmlhttpRequest({ method: "GET", url: url2, onload: withVars(cb2,processed2) }); } function cb2(evt){ ....... GM_xmlhttpRequest({ method: "GET", url: url3, onload: withVars(cb3,processed3) }); } function cb3(evt){ ....... GM_xmlhttpRequest({ method: "GET", url: url4, onload: withVars(cb4,processed4) }); } function cb3(evt){ ..... } GM_xmlhttpRequest({ method: "GET", url: url1, onload: cb1 });
.
The solution is better than many.
- Validation of data.
For example, you can write a decorator that will check that the type of the function's arguments matches a certain format string, and if it doesn't match, then convert / throw an error.
Then you can write code like the following:
var mult=fstrValidate(function(a,b){ return a*b; },"%d%d");
.
- Limit the frequency of execution functions
- Convenience. In many cases, the code using decorators will be cleaner, more beautiful and more efficient.
- Applications are limited to your imagination. If the task does not want to be solved / ugly is solved "in the forehead", then perhaps it can be solved with the help of decorators.
What to read
JavaScript.ru - Closuresarguments - MDNapply - MDNPS Thank you UFO for an invite.
UPD1: Added several uses.
UPD2: fixed a little code