Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a function return necessary to be called a Closure

Hey i came across this video on youtube http://www.youtube.com/watch?v=KRm-h6vcpxs

which basically explains IIFEs and closures. But what I am not understanding is whether i need to return a function in order to call it a closure.

E.x.

function a() {
    var i = 10;
    function b() {
       alert(i);
    }
}

in this case can i call it a closure as it is accessing the 'i' variable from the outer function's scope or do i need to return the function like this

return function b(){alert(i);}
like image 903
Nav Avatar asked May 16 '13 12:05

Nav


3 Answers

A closure is simply a function which holds its lexical environment and doesn't let it go until it itself dies.

Think of a closure as Uncle Scrooge:

enter image description here

Uncle Scrooge is a miser. He will never let go of his money.

Similarly a closure is also a miser. It will not let go of its variables until it dies itself.

For example:

function getCounter() {
    var count = 0;

    return function counter() {
        return ++count;
    };
}

var counter = getCounter();

See that function counter? The one returned by the getCounter function? That function is a miser. It will not let go of the count variable even though the count variable belongs to the getCounter function call and that function call has ended. Hence we call counter a closure.

See every function call may create variables. For example a call to the getCounter function creates a variable count. Now this variable count usually dies when the getCounter function ends.

However the counter function (which can access the count variable) doesn't allow it to die when the call to getCounter ends. This is because the counter function needs count. Hence it will only allow count to die after it dies itself.

Now the really interesting thing to notice here is that counter is born inside the call to getCounter. Hence even counter should die when the call to getCounter ends - but it doesn't. It lives on even after the call to getCounter ends because it escapes the scope (lifetime) of getCounter.

There are many ways in which counter can escape the scope of getCounter. The most common way is for getCounter to simply return counter. However there are many more ways. For example:

var counter;

function setCounter() {
    var count = 0;

    counter = function counter() {
        return ++count;
    };
}

setCounter();

Here the sister function of getCounter (which is aptly called setCounter) assigns a new counter function to the global counter variable. Hence the inner counter function escapes the scope of setCounter to become a closure.

Actually in JavaScript every function is a closure. However we don't realize this until we deal with functions which escape the scope of a parent function and keep some variable belonging to the parent function alive even after the call to the parent function ends.

For more information read this answer: https://stackoverflow.com/a/12931785/783743

like image 128
Aadit M Shah Avatar answered Sep 28 '22 16:09

Aadit M Shah


Returning the function changes nothing, what's important is creating it and calling it. That makes the closure, that is a link from the internal function to the scope where it was created (you can see it, in practice, as a pointer. It has the same effect of preventing the garbaging of the outer scope, for example).

like image 29
Denys Séguret Avatar answered Sep 28 '22 16:09

Denys Séguret


By definition of closure, the link from the function to its containing scope is enough. So basically creating the function makes it a closure, since that is where the link is created in JavaScript :-)

Yet, for utilizing this feature we do call the function from a different scope than what it was defined in - that's what the term "use a closure" in practise refers to. This can both be a lower or a higher scope - and the function does not necessarily need to be returned from the function where it was defined in.

Some examples:

var x = null;

function a() {
    var i = "from a";
    function b() {
        alert(i); // reference to variable from a's scope
    }
    function c() {
        var i = "c";
        // use from lower scope
        b(); // "from a" - not "c"
    }
    c();

    // export by argument passing
    [0].forEach(b); // "from a";
    // export by assigning to variable in higher scope
    x = b;
    // export by returning
    return b;
}
var y = a();
x(); // "from a"
y(); // "from a"
like image 24
Bergi Avatar answered Sep 28 '22 15:09

Bergi