Based on how they are built, can callbacks also be defined as closures?

In JavaScript, I know that closure can be defined as a nested function that has access to its containing function variables. For instance:

function outerFunction(x, y) { function innerFunction() { return x + y + 10; } return innerFunction; } 

Now the following code attaches a callback to the onreadystatechange property of the request object; however, I was interested, by definition, this is also considered a closure :

 /* This is a contrived example, I know. * Bear with me - it demonstrates the point I'm trying to convey. */ function submitHandler() { var oRequest = createRequest(); // assume I'm getting an instance of the xhr var sUsername = 'Tom'; // assume this is needed for work in the handler var This = this; oRequest.onreadystatechange = function() { This.handleResponse(oRequest, sUsername) } } function handleResponse(oResponse, sUsername) { if(oResponse.readyState === 4 && oResponse.status === 200) { // do work with the username } else { // we're not done yet... } } 

I understand that the handleResponse function handleResponse also be simply written as an anonymous function in the context of submitHandler , but I believe that more complex Ajax code can be more readable and easier to maintain if callbacks are defined outside the scope of the function that returns them back. Again, this is a contrived example that I use in the hope of simply demonstrating the essence of my question.

+4
source share
3 answers

Yes, you are correct in assuming that this definition is by definition.

It sounds like you know your stuff, but here is a nice, extensive article on closing javascript .

+3
source

I sincerely agree that too many built-in closure functions do not improve readability. On the other hand, I strongly dislike the var self = this style for writing closures, to which this is just an option, because it is still too verbose in your declaration, and you enter your own new keyword, whether this or self .

What you want is a curry / snap method.

 function $A(o) { var a = []; for (var i = 0; i < o.length; ++i) a.push(o[i]); return a; } Function.prototype.bind = function() { var _method = this; var a = $A(arguments) var o = a.shift(); return function() { return _method.apply(o, a.concat($A(arguments))); } } Function.prototype.curry = function() { var _method = this; var a = $A(arguments); return function() { return _method.apply(null, a.concat($A(arguments))); } } 

Methods taken from the Prototype library. I use them even in projects that do not use the Prototype library, as they are very useful!

In your case, this means instead of writing:

 var This = this; oRequest.onreadystatechange = function() { This.handleResponse(oRequest, sUsername) } 

now you can write:

 oRequest.onreadystatechange = this.handleResponse.curry(oRequest,sUsername); 

However, if you want to convey the meaning of this keyword, you can do it

 oRequest.onreadystatechange = this.handleResponse.bind(this,oRequest,sUsername); 

handleResponse when called will have the same this context as submitHandler .

+3
source

Your first example is not a closure. It would be if you returned innerFunction, but you execute the inner function and return the result.

The second example works and uses closure. One caveat with this particular technique is that in some versions of the browser you may run into a pretty serious memory leak (IE, of course, may be different). You will create a circular link between xhr stored in oRequest, onreadystatechange, referring to the function, and the function area, which is the area in which xhr is stored. Not only will xhr remain in memory, so will the answer, which if large (and especially if XML) can quickly shake the memory.

Set the onreadystatechange property to an empty global level function during response processing. It will break the circle.

+1
source

All Articles