In javascript function create scope. For example:
function scoped(){
let local = 10;
console.log(local) // this works local is within scope
}
scoped() // logs:
console.log(local) // error -- local doesn't exist out here.
Outside of scoped
local
doesn't exist.
A function inside a function has access to the entire scope. So this works:
function scoped() {
let local = 10;
function f() {
console.log(local) // this works local is within scope
}
f()
}
scoped()
But what happens if you return that function that references the scope of the function? It turns out that the inner function carries the whole scope with it. This is a closure:
function scoped(){
let local = 10;
function f(){
console.log(local) // this works local is within scope
}
return f
}
f = scoped()
f() // can still see local
// but nobody else out here can:
console.log(local) // still an error
This allows you to do some very slick things — an import one is that you can keep certain variables private, but still manipulate them with the closure.
For example here's a counter that doesn't require a variable in global scope:
function counter(){
let count = 0
return () => count++
}
let c = counter()
console.log(c()) // it can count but there's not count variable in scape
console.log(c())
console.log(c())
Doing this with a global count variable is messy and risks some other part of the code clashing with the global variable. Above, nothing other than the c
function can access the counter. In fact you can make several independent ones:
function counter(){
let count = 0
return () => count++
}
let c = counter()
let d = counter()
console.log("c:", c()) // it can count but there's not count variable in scape
console.log("c:", c())
console.log("d:", d()) // d has it's own closure
console.log("d:", d())
console.log("c:", c())
There's a lot you can do with closures and they're important in Javascript. It's worth taking the time to really understand them.