mjmitche
mjmitche

Reputation: 2067

Javascript closure

The following program returns "local" and, according to the tutorial Im reading, it is designed to demonstrate the phenomenon ofclosure`

What I don`t understand is why, at the end, in order to call parentfunction, it assigns it to the variable "child" and then calls "child."

Why doesn`t it work by just writing parentFunction(); at the end?

var variable = "top-level";
function parentFunction() {
  var variable = "local";
  function childFunction() {
    print(variable);
  }
  return childFunction;
}

var child = parentFunction();
child();

Upvotes: 3

Views: 270

Answers (3)

rsp
rsp

Reputation: 111336

parentFunction() returns another function which you assign to var child. Then, you call child() to invoke the function returned by the call to parentFunction().

Running just parentFunction(); at the end wouldn't do anything useful because you would just discard its return value which is a function. But this would work:

parentFunction()();

See this fiddle: http://jsfiddle.net/USCjn/

Update: A simpler example:

function outer() { // outer function returns a function
    return function() {
        alert('inner function called');
    }
}

x = outer(); // what is now in x? the inner function

// this is the same as saying:
//    x = function() {
//        alert('inner function called');
//    }

x(); // now the inner function is called

See this fiddle: http://jsfiddle.net/bBqPY/

Functions in JavaScript can return functions (that can return functions (that can return functions ...)). If you have a function that returns another function then it means that when you call the outer function what you get is the inner function but it is not called yet. You have to call the value that you got as a function to actually run the body of the inner function. So:

x = f();

means - run a function f and store what it returns (which may be a string, a number, an object, an array, or a function) in x. But this:

x = f()();

means - run a function f, expect it to return a function and run that returned function as well (the second parentheses) and store in x what the returned function returned.

The function f here is a higher order function because it returns another function. Functions can also take another functions as arguments. One of the most powerful ideas of functional programming languages in general and JavaScript in particular is that functions are just normal values like arrays or numbers that can be returned and passed around.

You have to first grasp the idea of higher order functions to understand closures and the event system in JavaScript.

2016 Update

Note that currently this:

function outer() {
    return function() {
        alert('inner function called');
    }
}

can be written as:

let outer = () => () => alert('inner function called');

using the ES6 arrow function syntax.

Upvotes: 6

user113716
user113716

Reputation: 322502

The point that is being demonstrated is that the function that was returned and assigned to child is still referencing the variable that was declared inside parentFunction instead of the one that was declared outside where child() is being invoked.

The only way to create a variable scope in javascript is in a function body. Normally the variable inside the parentFunction would have been discarded after the function returned.

But because you declared a function inside parentFunction that referenced variable in that scope and passed it out of parentFunction, the variable in the parentFunction is retained via the reference made in the new function.

This protects variable from outside manipulation except by functions that closed around it inside parentFunction.

Upvotes: 1

NT3RP
NT3RP

Reputation: 15370

The amazing part about closures is that an inner function (in this case, childFunction) can refer to variables outside of its scope (in this case, variable). parentFunction doesn't return the result of childFunction, but an actual reference to the function!

This means that when you do the following...

var child = parentFunction();

...now, child has a reference to childFunction, and childFunction still has access to any variables it had when the function was created, even if they no longer exist.

In order to have parentFunction call childFunction, you'd need to change your code as follows:

From...

return childFunction;

To:

return childFunction();

Douglas Crockford (Pioneer of JSON, among other things) has a whole article devoted to closures, and scoping in javascript, and it would be well worth it to check out his other articles on javascript.

Upvotes: 2

Related Questions