1

I have read a lot of example and question in stackoverflow about closure,but I feel like I'm not able to completely understand it, here is all I get:

function testClosure (s1,s2){
    return function(s3){
        return s1 +' '+ s2 +' '+s3;
    }
}

var t1 = testClosure("test","test2");


console.log(t1("test3")); //test test2 test3
  1. t1 is holding a function and scope chain of testClosure();
  2. t1 is returning anonymous function by itself.
  3. when t1 was called it puts inner function over testClosure(); to accept the last argument.
  4. s1,s2,s3 is lookup through the scope chain and return.

Is my understanding wrong?

enix
  • 113
  • 1
  • 8
  • 1
    #2 sounds wrong - t1 does not return a function, t1 IS an anon function which returns a string when called. – goat Jul 21 '13 at 18:19
  • @Ed Heal sorry, but what do you mean? – enix Jul 21 '13 at 18:20
  • @enix - Has your test proved that your logic is correct or not? – Ed Heal Jul 21 '13 at 18:34
  • An [answer with 1263 upvotes](http://stackoverflow.com/a/111200/1169519) to question "How do JavaScript closures work". – Teemu Jul 21 '13 at 18:36
  • 1
    He means have you tried plugging it into a computer and running it, and changing the code/playing with it until either a) you understood what was going on, or b) you saw something work a different way than you expected. A key part of your question that seems to be missing is "I expected it to do this, but it actually did this. Why?" As your question currently stands, it amounts to "explain closures to me." - in which case, the proper answer for a teacher to give you is: read a book, then play with them until you understand them. – Merlyn Morgan-Graham Jul 21 '13 at 18:38
  • @Ed Heal , Merlyn Morgan-Graham The answer is yes.I have tried a closure in many ways,but still confuse. – enix Jul 21 '13 at 18:48
  • Just a little search you get http://stackoverflow.com/questions/111102/how-do-javascript-closures-work – Ed Heal Jul 21 '13 at 18:50
  • @Ed Heal I have read it in the first but it not very clear for me. Maybe I'm not try hard enough to understand closure. – enix Jul 21 '13 at 19:26

2 Answers2

2
  1. You execute testClosure.
  2. testClosure creates and returns a new function. Since the function is created inside of another function, a closure is created and added to the new function's scope chain. The closure has access to the arguments that were passed into testClosure at the time of creation.
  3. variable t1 is assigned the returned function as its value.
  4. You call t1 and pass in an argument. Inside of t1 you reference the arguments that are part of the closure.
  5. t1 cannot find those values in its current context, so it looks at the next scope in the scope chain, which is the closure.
  6. t1 finds the values and finishes execution.
Zenwolf
  • 56
  • 2
  • `t1` *is* the closure – newacct Jul 22 '13 at 09:31
  • @newacct I think you are correct. The returned function is actually a function plus the variables available to the closure. When `t1` is executed its scope chain is something like: `[Activation Object Closure(s1, s2), Activation Object Global(window, etc)]`. Since the function assigned to `t1` includes the activation context of the closure as part of its scope chain, you could call `t1` a closure. – Zenwolf Jul 23 '13 at 05:44
  • 1
    `t1` is a closure because it is a function that refers to variables from outside of the function (`s1` and `s2`). On the other hand, you can say that `testClosure` is not a closure because it does not refer to any variable from outside of it. When `t1` is executed, you have its internal scope, and the parent of that is the scope of the execution of the `testClosure` function where `t1` was created, and then above that is the scope from outside the definition of `testClosure`. – newacct Jul 23 '13 at 08:29
0
  1. testClosure is invoking a named function that accepts two arguments and returns an anonymous function, and sets t1 to be an anonymous function.

t1 is now an anonymous function that can be invoked and accepts one argument. When t1 is invoked it builds your string param arguments from the name function and the anonymous function and returns the result.

When ever you invoke the named function testClosure it is creating a closure. When you invoke the anonymous function it has access to the enclosed name function string params, and returns the all 3 params as a built string .


Closures in JS is one of the most powerful implementations that JavaScript offers. Learning how to and where to implement or where a closure is needed is learned by baby steps over a period of time.

The bigger your JavaScript library grows the more you'll find yourself needing closures.

Closures allow you to put a specific piece of data in a context out of reach of other context, and I find myself using them more inside loops than anywhere else.

Anonymous functions and closures work together most of the time. The best way to learn closures is to keep very persistent in learning a little more each day about closures and when the time comes you'll finally get it when you find yourself in a situation that would need a closure.

Below is an example where I'm making an AJAX call to a photo album on a remote server. The success function of the AJAX call holds an array of photos for the album. for each loop I'm invoking a name function that will return an anonymous function. The anonymous function is set to the button click event.

Every new button added to the DOM will have access to it's own personal enclosed url string param.

It is vital to learn and understand closures to be a good JavaScript programmer.

function testClosure(url) {

    return function (ev) {

        document.getElementById('myImg').url = url || 'http://www.dummyurl/dummy.png';
    }
}

$.ajax({
    type: "post",
    url: "http://www.myurl.com",
    data: 'photoalbum' = 45,
    dataType: "json",
    success: function (photos) {

        for (var i = 0; i < photos.length; i++) {

            var btn = document.createElement('input');
            btn.type = 'button';
            btn.onclick = testClosure(photos[i].url);

            document.body.appendChild(btn);

        };
    }
});