Is a function return necessary to be called a Clos

2019-03-21 12:02发布

问题:

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);}

回答1:

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).



回答2:

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:

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



回答3:

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"


回答4:

The actual closure is a container for variables, so that a function can use variables from the scope where it is created.

Returning a function is one way of using it in a different scope from where it is created, but a more common use is when it's a callback from an asynchronous call.

Any situation where a function uses variables from one scope, and the function is used in a different scope uses a closure. Example:

var globalF; // a global variable

function x() { // just to have a local scope

  var local; // a local variable in the scope

  var f = function(){
    alert(local); // use the variable from the scope
  };

  globalF = f; // copy a reference to the function to the global variable

}

x(); // create the function
globalF(); // call the function

(This is only a demonstration of a closure, having a function set a global variable which is then used is not a good way to write actual code.)



回答5:

a collection of explanations of closure below. to me, the one from "tiger book" satisfies me most...metaphoric ones also help a lot, but only after encounterred this one...

  • closure: in set theory, a closure is a (smallest) set, on which some operations yields results also belongs to the set, so it's sort of "smallest closed society under certain operations".

a) sicp: in abstract algebra, where a set of elements is said to be closed under an operation if applying the operation to elements in the set produces an element that is again an element of the set. The Lisp community also (unfortunately) uses the word "closure" to describe a totally unrelated concept: a closure is an implementation technique for representing procedures with free variables.

b) wiki: a closure is a first class function which captures the lexical bindings of free variables in its defining environment. Once it has captured the lexical bindings the function becomes a closure because it "closes over" those variables.”

c) tiger book: a data structure on heap (instead of on stack) that contains both function pointer (MC) and environment pointer (EP), representing a function variable;

d) on lisp: a combination of a function and a set of variable bindings is called a closure; closures are functions with local state;

e) google i/o video: similar to a instance of a class, in which the data (instance obj) encapsulates code (vtab), where in case of closure, the code (function variable) encapsulates data.

f) the encapsulated data is private to the function variable, implying closure can be used for data hiding.

g) closure in non-functional programming languages: callback with cookie in C is a similar construct, also the glib "closure": a glib closure is a data structure encapsulating similar things: a signal callback pointer, a cookie the private data, and a destructor of the closure (as there is no GC in C).

h) tiger book: "higher-order function" and "nested function scope" together require a solution to the case that a dad function returns a kid function which refers to variables in the scope of its dad implying that even dad returns the variables in its scope cannot be "popup" from the stack...the solution is to allocate closures in heap.

i) Greg Michaelson ($10.15): (in lisp implementation), closure is a way to identify the relationship betw free variables and lexical bound variables, when it's necessary (as often needed) to return a function value with free variables frozen to values from the defining scope.

j) histroy and etymology: Peter J. Landin defined the term closure in 1964 as having an environment part and a control part as used by his SECD machine for evaluating expressions. Joel Moses credits Landin with introducing the term closure to refer to a lambda expression whose open bindings (free variables) have been closed by (or bound in) the lexical environment, resulting in a closed expression, or closure. This usage was subsequently adopted by Sussman and Steele when they defined Scheme in 1975, and became widespread.