1

I have the following code :

var x = 6;
var y = 4;
var a = function(b) { 
    return function(c) { 
        return y + b + c; 
    } 
};

x = 2;
y = 5;

var fn = a(x);

x = 1;
y = 3;

I was asked to figure out what unknown needs to be in order for fn(unknown) to output 10 :

console.log(fn(unknown)); // This should output 10

I know unknown needs to be 5 in order for the fn output to be 10, but can someone explain why?

I'm sure it has to do with enclosure but not quite understand how the variables get assigned at different stages.

John Slegers
  • 45,213
  • 22
  • 199
  • 169
akantoword
  • 2,824
  • 8
  • 26
  • 43

3 Answers3

3

The simplest description of a closure I've heard is:

It's a way for a function to have indefinite access to the environment it was created in.

So in:

var a = function(b) {            /* "outer"  aka  "functionofb" */
    return function(c) {         /* "inner"  aka  "functionofc" */
        return y + b + c; 
    } 
};

We're going see how this gives the inner function indefinite access to (a copy of) variable 'b' as it existed when inner sprang into life. (In this example the inner function never changes the value of its copy of 'b', but it could.)

So to walk through your example, lets start Here:

     x = 2;
var fn = a(x);

The variable a "points" to an un-named (anonymous) function (the one with 'b' as an arg), so this is essentially:

fn = functionofb(x);

or :

fn = functionofb(2);

Now 'functionofb' is a function which returns a function. The function it returns is:

function(c) { 
    return y + b + c; 
}

(which is also anonymous, so we will call it `functionofc')

So:

function(c) { 
    return y + 2 + c;       /* here 'b's value is 'captured' by the closure */
}

Then we have:

y = 3;

And do:

fn(5);

Which is just:

functionofc(5);

which gives us:

return y + 2 + c;

Or:

return 3 + 2 + 5;            /* 'y' was never captured, the current value is used */

Which is the desired answer:

10

Everything else are just red herrings.

For a more complete discussion of JavaScript closures in general see How do JavaScript closures work?

Community
  • 1
  • 1
John Hascall
  • 9,176
  • 6
  • 48
  • 72
2

When you do this ...

var fn = a(x);

... the variable fn becomes equal to ...

function(c) { 
    return y + 2 + c; 
} 

... because x is equal to 2 at that moment, and the value of x is captured (fixed) when you execute function a.

So, when you execute fn(5) with variable y being equal to 3 at the very moment you're running function fn, that means that function will do this...

return 3 + 2 + 5; 

Since 3 + 2 + 5 = 10, that means your output is 10.


Note 1 :

fn(5) would have returned 12 if you had ran it before y = 3;, because the value of y was 5 at that time. See this Fiddle for a demo.


Note 2 :

For more info on closures, see also this question :

How do JavaScript closures work?

Community
  • 1
  • 1
John Slegers
  • 45,213
  • 22
  • 199
  • 169
1

You would need to pass in 5 as unknown.

Brief definition of closure for completeness

From This SO link

  • a closure is the local variables for a function — kept alive after the function has returned, or
  • a closure is a stack-frame which is not deallocated when the function returns (as if a 'stack-frame' were malloc'ed instead of being on the stack!).

Numbers are pass-by-value in javascript

The b argument that is passed to a() is saved in the closure that a returns. So in your example, b is saved to be the value of x, or 2. This is because Numbers in javascript are pass-by-value. This means that changing x DOES NOT change the value of b inside the closure that a returns.

Short example for clarity:

var a = function(x) {
  return function() {
    return x + 1;
  };
};
var x1 = 1;
var fn1 = a(x1); // x1 is passed by value, so x inside the closure is its own copy of 1
x1 = 2 // no effect on the next line
console.log(fn1()) // prints 2, does NOT print 3

References to objects in the global scope within a closure

The y variable in the closure that a returns references y directly from the global scope, so a change in y in the global scope alters the value of y in the closure that a returns.

Short Example for clarity:

var x = 1;
var a = function() {
  return x + 1;
};
console.log(a()); // prints 2, since x is still 1

x = 2;
console.log(a()); // prints 3, since the a() closure references the global x

Putting it all together

b is a copy which stays 2 for the entirety of your example, y references a global variable that may change it's value after calling a(), and c will be the value of unknown, since it's the argument to the closure that a() returns.

You example for completeness:

var x = 6;
var y = 4;
var a = function(b) { 
    return function(c) { 
        return y + b + c; 
    } 
};

x = 2;
y = 5;

var fn = a(x);

x = 1;
y = 3;
console.log(fn(5)) // prints 10 = y + b + c
                   //             3 + 2 + 5
Frank Bryce
  • 8,076
  • 4
  • 38
  • 56
  • @jlei did my post, and the other clarify your question about closures? Is anything still unclear? – Frank Bryce Feb 22 '16 at 19:03
  • so to clarify, b saved its value because it was passed as a parameter while y didn't because it referenced a global variable? – akantoword Feb 25 '16 at 00:36
  • @jlei I'd say that's a succinct explanation, yes. Another way to think of it is that scopes are areas of your code to set variables. If you leave the area that a variable was set in then you no longer can change the value of that variable. That is why `b` can't be changed after you leave the closure. The global variable never "leaves scope" so a change to it will affect all places of the code which referenced it. – Frank Bryce Feb 25 '16 at 03:25
  • thanks for the explanation John! – akantoword Feb 26 '16 at 01:08
  • @jlei you are welcome :) – Frank Bryce Feb 26 '16 at 02:31