deldalton Posted April 25, 2013 Share Posted April 25, 2013 (edited) 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 April 25, 2013 by deldalton Link to comment Share on other sites More sharing options...
davej Posted April 25, 2013 Share Posted April 25, 2013 (edited) 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 April 25, 2013 by davej Link to comment Share on other sites More sharing options...
justsomeguy Posted April 25, 2013 Share Posted April 25, 2013 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 More sharing options...
davej Posted April 25, 2013 Share Posted April 25, 2013 (edited) 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 April 25, 2013 by davej Link to comment Share on other sites More sharing options...
justsomeguy Posted April 25, 2013 Share Posted April 25, 2013 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 More sharing options...
davej Posted April 25, 2013 Share Posted April 25, 2013 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 More sharing options...
jeffman Posted April 25, 2013 Share Posted April 25, 2013 (edited) 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 April 25, 2013 by Deirdre's Dad Link to comment Share on other sites More sharing options...
jeffman Posted April 25, 2013 Share Posted April 25, 2013 (edited) 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 April 25, 2013 by Deirdre's Dad Link to comment Share on other sites More sharing options...
justsomeguy Posted April 25, 2013 Share Posted April 25, 2013 element.event = function(){...}That assigns an anonymous function. element.event = (function(){...})();That executes an anonymous function and assigns whatever it returns, which should be another function. Link to comment Share on other sites More sharing options...
davej Posted April 26, 2013 Share Posted April 26, 2013 (edited) 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 April 26, 2013 by davej Link to comment Share on other sites More sharing options...
justsomeguy Posted April 26, 2013 Share Posted April 26, 2013 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 More sharing options...
justsomeguy Posted April 26, 2013 Share Posted April 26, 2013 With most files cached, that application will start up and finish drawing the interface in less than 400ms, so browsers are certainly up to the task for whatever code you want to throw at them. Link to comment Share on other sites More sharing options...
davej Posted April 26, 2013 Share Posted April 26, 2013 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 More sharing options...
justsomeguy Posted April 26, 2013 Share Posted April 26, 2013 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 More sharing options...
justsomeguy Posted April 26, 2013 Share Posted April 26, 2013 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 More sharing options...
davej Posted April 26, 2013 Share Posted April 26, 2013 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 More sharing options...
justsomeguy Posted April 26, 2013 Share Posted April 26, 2013 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 More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now