Jump to content

Function Returning Function. Unnecessary?


deldalton
 Share

Recommended Posts

Okay. So, in my ongoing attempt to learn JavaScript, I've been given the following task. Write a function greaterThan, which takes one argument, a number, and returns a function that represents a test. When this returned function is called with a single number as an argument, it returns a boolean: true if the given number is greater than the number that was used to create the test function, and false otherwise. Please see the solution they provided below.

function greaterThan(x) {[indent=1]return function(y) {[/indent][indent=2]return y > x;[/indent][indent=1]};[/indent]} var greaterThanTen = greaterThan(10); show(greaterThanTen(9));

Why would I write a function, like the one above, when I could write a function like the one below?

function greaterThan(x, y) {[indent=1]return y > x;[/indent]}; show(greaterThan(10, 9));

And, secondly, how is the first code actually being interpreted? Why do we have to create a new variable storing the value of "greaterThan(10)"? Why can't we simply write

show(greaterThan(10(9)));

? Perhaps I need to find some better resources to study from. I'm clearly missing something.

Edited by deldalton
Link to comment
Share on other sites

I am curious to see what the experts here say. To me it looks foolish and unnecessary. If you did need to dynamically modify a function I think there are better, more straightforward, ways to do it. If possible I would simply use a global. I'm supposing those [indents] are from your text editor.

Edited by davej
Link to comment
Share on other sites

That's just a basic example, there would be more complex situations where it would make sense to create a temporary function for each one. That's just doing a single line of comparison, so it's not really a real-world example of using closures.

Why do we have to create a new variable storing the value of "greaterThan(10)"?
You don't have to save it, but if you're going to call that function more than once then it makes sense to save it instead of creating a new one every time. If you didn't save it then you would call it like this: show(greaterThan(10)(9)); Or if it doesn't like that syntax, this would work: show((greaterThan(10))(9));
Link to comment
Share on other sites

So...http://en.wikipedia....uter_science%29 Some examples make it seem that this is just a way to avoid using a local static variable. I'm guessing it is more than that? In this code...

document.getElementById('button').onclick = (function() {	// init the count to 0	var count = 0;  	return function(e) {		//count		count++;  		if (count === 3) {			// do something every third time			alert("Third time's the charm!");			//reset counter			count = 0;		}	};})();

Also you have the overall form... element.event = (...)(); ...what is that? I see that sort of thing in jQuery and I've never understood it.

Edited by davej
Link to comment
Share on other sites

In that code, it avoids using a global variable called count. The variable is defined within the scope that the function runs, so each time that function runs it has access to count. It gets a little strange to think about, but with that code count would be a global variable for the function, but not for everything else. It is global to the scope it was defined in, which is the scope that the outer function is running in.

element.event = (...)();
It's defining an anonymous function and executing it immediately, so that everything inside runs in a new scope. There aren't any conflicts with any other variables.
Link to comment
Share on other sites

I have tended to apply events to either named functions or anonymous functions... element.event = function(){...} ...but others seem to use... element.event = (function(){...})(); ...how is that different?

Link to comment
Share on other sites

It's defining an anonymous function and executing it immediately, so that everything inside runs in a new scope. There aren't any conflicts with any other variables.
In other words, there are two functions here. Think of one as the outer function; think of the other as the inner function. The typical way of assigning an event listener would set the value of onlick to a basic function that has no inner function. Here, by executing the outer function immediately, and setting its return value to the inner function, the value of onclick becomes the inner function. In addition, a "static" variable called 'count' gets created along with it; 'count' is not visible in any other scope. The trick with 'count' is the whole reason for assigning the function this way. It saves you from creating a global variable that might get accidentally overwritten. A good trick for third-party libraries. Edited by Deirdre's Dad
Link to comment
Share on other sites

FWIW, my own strategy would be to set the value of onclick to the inner function to begin with, and make the counter a property of 'button.' You'd reference it as this.count. As with any object available in the global space, that's a good idea only if you're sure there won't be an identifier collision.

Edited by Deirdre's Dad
Link to comment
Share on other sites

Self modifying code... I thought that was supposed to be an ~evil~ thing? Is asking the browser interpreter to redefine functions all the time a very efficient thing to do? If local static variables are so critical then why doesn't Javascript have them?

Edited by davej
Link to comment
Share on other sites

Is asking the browser interpreter to redefine functions all the time a very efficient thing to do?
I'm not sure what you're referring to. If you're asking the browser to do anything "all the time" then that's not very efficient. Anonymous function are not inherently inefficient, they are typically preferred when you only need to run a function once (e.g., passing a function as an event handler, there's no reason to make that a named function if that's the only place you're using it). You might be surprised how fast most Javascript engines are these days though. The interface for my application is a Javascript file that has over 40,000 lines at a total of about 1.5MB. It has closures, anonymous functions, extending objects, dynamic scoping, everything you can think of. And that loads on top of ExtJS, which is about another 40,000 lines and over 1MB. It all gets executed very quickly. Of course, like any language, it's possible to write terribly inefficient Javascript, but that doesn't mean you need to.
If local static variables are so critical then why doesn't Javascript have them?
Javascript is a prototype-based language, it lacks a lot of things from other paradigms (like actual classes). That's just the way it is, there's no language that contains all features from every paradigm. A local static variable can be implemented in Javascript exactly the way you're seeing it, by running the code in a new scope.
Link to comment
Share on other sites

I'm not sure what you're referring to. If you're asking the browser to do anything "all the time" then that's not very efficient. Anonymous function are not inherently inefficient, they are typically preferred when you only need to run a function once...
What I meant is rather than storing a static local variable the interpreter is given an entire new function to store each time the (...)() function is executed. I'm usually pretty sparse with my events but some people have events firing on mouse movement, etc...
Link to comment
Share on other sites

That function only gets executed once. The anonymous function gets defined, executed, it returns another function, and that returned function gets set as the event handler. It's not executing the outer function every time the event fires, it is executing whatever that function returned (another function). With the code in post 4, that outer function only executes once, immediately after it gets defined. It returns another function, and that function is the click event handler. If the outer function ran every time then count would always get reset to 0.

Link to comment
Share on other sites

Also, note that with that code, it is not possible to access that count variable from anywhere other than the returned event handler. That function runs in a certain scope which is not possible to reference from any other scope. Sometimes it's a wonder that Javascript garbage collection works as well as it does - how does it really determine when it can destroy and clean up that scope? (there's a good answer for that, but it still gets fairly confusing)

Link to comment
Share on other sites

Ok, so then it isn't redefining the function -- it is just providing a trick variable that is caught in some sort of "scope bubble."

btnelement.onclick = (function() {	    var count = 0;	    return function() {  count++; alert(count); }	    };})();

...becomes...

btnelement.onclick = function() {  count++; alert(count); };

Is there any reason for that inner e function parameter in the original? Is there any other place the (...)() function notation will be seen?

Link to comment
Share on other sites

It sort of becomes that, the only thing to add is that it runs in a scope where count is defined and doesn't change other than by that function. Sort of if count was a global variable, but in this case there's no way for anything else to overwrite it.

Is there any reason for that inner e function parameter in the original?
It's the event object that gets passed to event handlers.
Is there any other place the (...)() function notation will be seen?
I use that any time I want to run a piece of code without worrying about interfering or overwriting other variables. Code that is meant to be distributed and used with other code often uses that to make sure it doesn't conflict with anything else. Some people use that for jQuery code, so that their code doesn't conflict with another framework that uses "$" as an identifier, e.g.:
(function ($) {  ...})(jQuery);

That defines a function that takes a single parameter, which it calls "$", and it gets passed the jQuery object when it runs. That way, the code inside can use $ to refer to jQuery (like the vast majority of jQuery code examples show), but it passes the jQuery object into that function to use as the parameter instead of having that code in the global scope and just expecting $ to point to jQuery.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...