DEV Community

HawiCaesar
HawiCaesar

Posted on

No, I don't know what closures are...yet

I want share an interesting lesson I learned on closures. The journey to this lesson all started when I commented on a PR and the author of the PR said he added the extra () to a function this.handleToggle as the function was a closure. This scratched my brain for a while. I mean, I knew what closures were or at least an idea of it. I decided to write it down in my note book as I would come back to it later. I then remembered a friend of mine recommended I start here when looking into js. I quickly went to this github repo and looked for the chapter on closures. The text book definition I thought I would find was not there. However, Kyle Simpson used examples and explained "to me like I am 5" I grasped the concept.

An interesting code snippet that baffled me though was this

for (var i=1; i<=5; i++) {
    setTimeout(() => {
        console.log( i );
    }, 100 );
}
Enter fullscreen mode Exit fullscreen mode

which you might think prints out

1
2
3
4
5
Enter fullscreen mode Exit fullscreen mode

This actually prints out 6 five times on the console. Try it out. Weird ? Not really. I simply wanted to see the above output. I played around with it and still got 6 five times on the console. Why did not continue reading is because I thought I knew that what I read at first was enough to try out the loop example without reading further. I even added a 0 to have to timeout not have any delay. No luck! I continued reading Kyle Simpsons book and found out he had a solution to this. It turns out what I (and many developers may have done) was trying to

imply that each iteration of the loop "captures" its own copy of i, at the time of the iteration. But, the way scope works, all 5 of those functions, though they are defined separately in each loop iteration, all are closed over the same shared global scope, which has, in fact, only one i in it.

Kyle Simpson provided a solution by either using an IIFE or the ES6 sibling of var, let.

using an IIFE

for (var i=1; i<=5; i++) {
    (function(j){
        setTimeout(() => {
            console.log( j );
        }, j );
    })( i );
}
Enter fullscreen mode Exit fullscreen mode

using let

for (let i=1; i<=5; i++) {
    setTimeout(() => {
        console.log( i );
    }, 100 );
}
Enter fullscreen mode Exit fullscreen mode

I approached a senior dev and he explained the same issue only that emphasized how dangerous var can be. var was hoisting the value of i and therefore the the value of 6 is always printed. What I forgot ask is this. For the first code snippet, is the whole loop running such that var does get to 6 and then run all the setTimeouts later and then display 6 as the value of i ?

Finally what closures are:

Those who like to hook onto a definition, I did a little digging and a post by Eric Elliot who explains it well here.

Eric Elliot

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function.

I got access to one of Kyle Simpson videos and he explains as follows

A closure is when a function 'remembers' its lexical scope even when that function is executed well outside it the lexical scope.

I hope they make sense and I encourage you to read up more on
"You Don't Know Js, Closures"
Master the JavaScript Interview: What is a Closure?

Discussion (3)

Collapse
devinamarsh profile image
Devin

I had to read how closures worked about 6 different times before I really understood them. Every time I would walk away thinking I got it, only to realize I couldn't really explain it. I think finding a need for it in my code was what finally made it break through for me. The same happened with currying and partial application.

This code is what finally got me to understand partial application:

    const openRenameModal = () => setModalMode(CONST.MODAL_MODES.RENAME);
    const openColorModal  = () => setModalMode(CONST.MODAL_MODES.COLOR);
    const openDeleteModal = () => setModalMode(CONST.MODAL_MODES.DELETE);

Putting something into practice can be a much easier way to learn that lots of "foo"s and "bar"s.

Collapse
kayis profile image
K (he/him)

Took me about a month to wrap my head around this.

Also, half a year to get monads.

JS isn't as easy as it sometimes seems xD

Collapse
christiankaindl profile image
Christian Kaindl

Yeah, the You Don't Know JS series is awesome 🔥