I have a few closure questions. I have read many articles on closure, but sometimes even those differ on what closure is/does.
1 Are all functions closures?
2 What is the limit of an inner function’s ability to read the scope or environment of its a parent function(s)? Can it only reach one level up (from inner to the first outer function) plus use the global scope, or is every single scope up to to the global scope? (Imagine you have a function inside of function inside of function inside of a function, etc. What is the limit? Is it one level up or is it infinite?)
3 Terminology with closures varies. What is the correct way to refer to the “scope” that a closure has access to? Is it scope, environment, outer function, etc? And is there a proper way to refer to what a closure does (“A closure “closes” the scope”)?
I’ll try, but closures are a difficult concept and I’m still not sure if I’ve completely gotten my head around them.
I can safely say that the answer to your second question is “there’s no limit”. A function can always look at its outer scope (and the one above and above, up to the global scope).
Concerning question 1, I’d say it depends on what the function does and if you declare any variables inside of them.
A function like this:
function log(stuff){
console.log(stuff)
}
doesn’t really close over anything. stuff is passed to the function from the outer scope, and therefore exists in the outer scope.
A function like
function locker(){
let secretStuff = 'unmentionable';
return 'You will never know';
}
does close over the secretStuff variable, but the variable “dies” after the function executed. There’s no reference anymore to it anywhere.
A case where the variable doesn’t die is when there’s still a reference to it somewhere:
function locker(){
let secretStuff = 'unmentionable';
return function(){
return secretStuff
}
}
const iKnow = locker;
const blabberSecret = iKnow();
The locker function runs exactly once, when blabberSecret is assigned, and then dies. But even if the function is “done” and will never run again, a reference to secretStuff is still in memory. blabberSecret knows it now, because it points to the anonymous function that was returned by the locker function, and that anonymous function has the value of secretStuff safely stored.
I hope I said something wrong somewhere so that others with more knowledge will feel compelled to correct me
A closure is a function + the free variables floating around in its parent function. that’s the closure. The function is just a function. But practically, that makes no difference, so yes, all functions are going to be closures in a language that supports them (JavaScript here).
Just the free variables in the containing parent function (“one level up”). That itself can be closure, and so on.
Scope/lexical environment/outer function all describe what it is, Lexical environment I guess is correct.
Edit: just re 2 – if it could contain all variables from all scopes above the parent, then that would be an issue. It’s not really feasible to do that, but if it were, single closures down the tree would all potentially close over almost all of a given program, which would cause huge memory leaks
Thanks for the help both of you. I think I was able to understand things a bit more.
When I think of closures as simply scope, instead of some distinct thing, they make a bit more sense to me. So that is why I asked if all functions are closures - that they close on their outer environment, upward to the global scope.
This seems a technical and perhaps only semantic distinction, but for a function like this, like @jdisco wrote
function log(stuff){
console.log(stuff)
}
I am not sure if it “closes” on its outer environment scope in practice, but it does have access to the outer scope, even if it is not using it. So whether this is technically a closure I don’t know, but it seems so, because the function (or the function’s scope) “closes” on the outer scope, even if it doesn’t make use of it.
If I am getting anything wrong, or anyone has something to add, please let me know!
Just the immediate environment, not upwards beyond that.
Yes, you’re correct here. What is defined isn’t a closure, it’s just a function. But when that function is evaluated, a closure is created. I assume it’s always going to be closure in JS (ie the JS interpreter is going to store some record that has a slot for the function + a slot for the free variables in memory), it seems simpler to just do that every time from a programming POV, but I don’t know. As I say, practically doesn’t make a lot of difference