Trying to understand closures

Trying to understand closures
0

#1

I’ve recently picked up Eloquent JavaScript and i’m trying to understand closures.

In the book he gives an example:

function multiplier(factor) {
  return number => number * factor;
}

let twice = multiplier(2);
console.log(twice(5));
// → 10

…and my understanding is that the line let twice = multiplier(2) is somehow storing the value, and then later when twice(5) is called the 2 values are multiplied together.

My question is, where is the value 2 stored in this instance? Is it in either the number or factor variables within the function scope? Is it stored in the twice variable?

Also, if factor is 2, wouldn’t number just be undefined and shouldn’t that return NaN to twice?

Sorry if this doesn’t make any sense but I feel like i’m on the verge of finally understanding closures!


#2

People like to make a big deal about closures, but once things start to click you start to understand that nothing special is happening.

When you write let twice = multiplier(2) you are passing 2 as an argument, and that argument is available to the function that is returned back to you. I think the code is slightly more intuitive by dropping the arrow function:

function multiplier(factor) {
   // You could imagine that factor, which is 2 in your example, is stored here, and remains available to the function below this line no matter where that function is called from. 
   return function(number) {
      // and this is where number is available
      return number * factor
   }
}

Keep in mind that twice is a function. If you called twice() without any args then factor would be undefined, but in your example a 5 is being passed in.


#3

Closures sounds like some fancy complex concept, but the idea is simple. It all boils down to scope and how javascript deals with it.

Just to make things clear. The example itself could of been written a slightly more “consistent” way. There are a number of ways of writing this code that performs the same (at least in this context), and really the original programmer choose a “mixed” approach IMO. The following are alternatives of writing the same code basically.
Either:

// the "classic" oldschool way
function multiplier(factor) {
  return function (number) { 
    return number * factor;
  }
}
let twice = multiplier(2);
console.log(twice(5));
// → 10

And the “syntax-surgar” way, using only arrow functions

const multiplier = factor => {
  return number => number * factor;
}
let twice = multiplier(2);
console.log(twice(5)); // 10

or the super syntax sugar concise way

const multiplier = factor => 
  number => number * factor;
const twice = multiplier(2);
console.log(twice(5));//10

Now ontop the idea of closures, which can be abused to do stuff like this:

console.log(whoa(1)(2)(3)); // [1,2,3]

You might be like “whoa is that even code?” and yea, JS is funky like that.
The definition is closures are functions that have access to an outer functions scope, which might be confusing, but as @RadDog25 said, it’s much simplier once you figure out the concept. But first lets look at the implementation of the above code which will be used in the breakdown in a bit:

// remember, arrow functions are syntax sugar over normal functions
const whoa = (first) => {
  return (second) => {
    return (third) => {
      return [first, second, third]
    }
  }
}
console.log(whoa(1)(2)(3)); // [1,2,3]

So, the easiest way to get around to understanding closures is to imaging yourself as the js runtime going over this code. What makes it kinda confusing is your basically “reading up” the code when your executing it, instead of the usual top down. So let’s follow the JS runtime step by step as it goes over this code.

  1. It reads the script top to bottom.
  • This step is somewhat obvious, first it sees the const whoa and sees its defined as a function, and dives into it to see how its defined. That’s all fine and good as it comes out of all the nested functions “knowing” how the functions are defined. Theres a reason why I wont go “into it” because technically the code within these functions is just a “value”, but that value just happens to be a function. Functions don’t “do” anything until they are called. Now you might be like “But aren’t they called yet” and Ill say no, they have only been defined. We call them later.
  1. The final line (console.log(whoa(1)(2)(3))) is were we actually start “execution”. It all starts with a rather innocent character ( after .log You might not think much about this, but just like math, parenthesis basically are telling the js runtime to “execute and evaluate whats in-side”, and whats inside is this code: whoa(1)(2)(3). After executing this value, we pass the value of whoa(1)(2)(3) to .log to print out. Nothing fancy here, whoa could of been a string and we’d be done, but were not.
  2. Now we execute the `whoa(1)(2)(3) code, and this is where thing start going into what we defined at the start.
  • With this function we find another ( (just left of the 1) which again tells the JS runtime to “execute” the function essentially. Now looking at the whoa function definition we see basically this:
whoa = (first) => {
  return <VALUE>;
}

Where the <VALUE> is the inner function. That’s fine, what we know about functions is we return whats after the return on the same line, so lets do that and see how the whoa code in the .log() statement looks to see if were “done”:
console.log(<VALUE>(2)(3))

Now you might notice something here, if <VALUE> was the name of a function it would look like: myFunction(2)(3) and we’ve already seen that before… But lets go onto the next "step
4. We need to execute the next ( after our <VALUE> code, and lets get real <VALUE> is a function right? So we execute the “inner function”.
Now our inner function (the one with second) is boring too, as it’s defined just as:

(second) => {
  return <VALUE_2>;
}

And again <VALUE_2> is actually just another function. and the “value” within the .log looks more or less like this:
console.log(<VALUE_2>(3)
where the <VALUE_2> is the result of the thewhoa` function AND it’s inner function!

  1. We proceed execute the following for the final nested function:
(third) => {
  return [first, second, third]
}

Now this is where the definition of a closure comes in, and where everything comes together.
Within this code snippet the JS runtime has no idea what first or second is, it only knows what third is, as it’s passed. (in our whoa example it just happens to be 3) So it looks outside of the current scope of code to see if it can find one first. So it goes to the second code snippet:

(first) => {
  // first is here!, and it was executed way back earlier with the value of 1
  (second) => {
  // no "first" in this scope
    return (third) => { // third is passed as 3
      return [first, second, third];
    };
  }
}

So it adds the “first” value (1) into the returned array after looking into the first functions scope, even tho the second inner function didn’t have it
Now this is where closures will make more sense, if the first variable didn’t exist in my code at all the JS runtime will go to the global scope (outside of all the code I’ve written) and see if it exists there The global scope can have the variable as well, so you can essentially think of all your code running in a “global” function (!!!)

  1. Now to finalize this lets get the value for the second part of the array, which only “looks up” to the parent inner function of where we are currently “executing” (just as a reminder were’ still “in” the third inner function.
(second) => { // second had a value of 2 remember?
  // Oh we only had to look up to the scope "above" or "outside" of ours
  return (third) => {
    return [1, second, third];
  };
}
  1. We add our “third” value into the array and return it:
(third) => { // we passed 3 as our last (3)
  return [1, 2, 3];
};
  1. Now finally we return this value back to console.log and exit our script.
    console.log([1,2,3])

So to summarize this long post, closures can access the outer scopes to “get stuff” from the outer scopes, in the same way you can access stuff in the global scope. It also matters that your “inside” of something, as my whoa example shows when you execute functions that return functions and access the parent scopes at the same time.

Hopefully that helps some by providing a rather verbose explanation of a rather unusual code example.

PS here’s the codepen for the above code if you wanted to play around with it, it also has some more console.logs


#4

So basically closure is that you can access parent function’s body even after it stops executing.
So here we divide this process to steps. first only care about invoked function "multiplier(2)

  1. when you invoked function code in function body starts being executed it sees return keyword which means return whatever in this line so it returns new function argument times factor

  2. Second step is storing whatever comes back from function call. we are storing result in twice variable. as returned value is
    const number = (number) {
    number * 2 // I used 2 instead factor in this case for clarification
    }
    this function is not called yet it is stored in twice variable so whenever with whatever value you call returned function result will be number *2.
    twice(10) // 20
    twice(0) // 0

if you call multiplier function again but this time with other value like 10
this time number * 10 will be result as long as you do not call multiplier() function with different values


#5

You Don’t Know JS: Scope & Closures

I would suggest viewing all of this, but in case you just want the Closure part it starts at 19:00


#6

Thanks so much for your explanations, it’s been a huge help! Think I finally understand closures, now it’s just looking for opportunities to use them in actual code.