I want to make sure to master the concept of variable scope. Ideally, I'd like a definition of the form:
- x is the scope of identifier i just in case x ...
or of the form:
- the scope of identifier i is identical to ...
Although I am new to programming, I have read through some general material on variable scope and some material on variable scope in JavaScript (including this). However, I cannot seem to find a precise, descriptive definition. I have tried to come up with my own, but I've noticed that it does not always fit how others speak.
It is probably best to illustrate my current understanding. Let's take 'context' nearly as a primitive to mean something like a region of code delimited by curly braces. Think about the main region of code, functions, and blocks (I bet I've left some things out). Let's think of variables in the broadest sense to include variables, parameters, and function names or identifiers, more generally. Then:
- the scope of a variable
v
is identical to the set of contexts within whichv
is accessible.
Here's an example:
let a = 'foo';
function bar(param) {
param += 2;
function newFunc() {
console.log(param);
}
newFunc();
}
Here we have three contexts:
- The main context.
- The context that results from defining the
bar
function. - The context that results from defining the
newFunc
function.
According to the above attempt at a definition, we have two scopes:
- There is the global scope of built-in names like
console
,null
, etc, as well as defined namesa
andbar
. This scope is the set of contexts 1, 2, and 3 above. - There is the scope of
param
andnewFunc
. This scope is the set of contexts 2 and 3 above.
No scope comprises only context 3 because there is no new variable defined in context 3.
So, defining a function creates a context. The scope of a variable includes that new context just in case the variable is accessible from that context.
However, I know that people will say that the above code example includes 3 scopes and more or less identify those scopes with what I've called 'context'. However, I cannot make sense of this, and I do not know what precise definition of variable scope permits them to say there are 3 scopes in the above. It seems strange to me to talk about scope without talking about a variable/identifier's scope. More precisely, it seems context is undoubtedly independent of variables, but scope is not. Scope is a property of variables/identifiers; that's why we are talking about variable scope or the scope of some identifier or another when we talk about scope.
I have also seen people talk about variables going in and out of scope. To me, variables have a scope, period. The program moves from context to context and thereby moves in and out of the variables' scopes. Variables go in and out of context as the program runs. They might even always be in context (if they have a global scope) or always out of context (e.g., if they have function scope and that function is never invoked). But it seems inappropriate to say that variables go in and out of scope or that a variable's scope changes.
It has occurred to me that it is not correct to speak of the scope of an identifier unless there is a unique context within which an identifier is accessible. So, instead, we might have
- S is a scope of identifier
v
just in case S is a context within whichv
is accessible.
Given this definition, we have three scopes:
- Context 1 is a scope of
a
andbar
. - Context 2 is a scope of
a
,bar
,param
, andnewFunc
. - Context 3 is a scope of
a
,bar
,param
, andnewFunc
.
In the above code, there are no contexts for which it is true that it is the scope of an identifier. For that to be the case, there would have to be a unique context for which the identifier is accessible. For example, if the code omitted newFun
, then there wouldn't be a third context, and context 2 would be the scope of param
and newFunc
.
So, defining a function creates a context. The context is a scope of a variable just in case the variable is accessible within that new context.
There are problems here, though, too. Consider the following code:
for (let i = 0; i < 5; i += 1) {
if (i % 2 === 0) {
console.log(i);
}
}
I have seen people say that there are three contexts here, but the inner, nested one of the if
block is not a scope. But on the definition I just gave, that block would be a scope of i
as well as built-ins like console
.
That's where I am currently. Thanks, in advance, for your respectful help.
UPDATE
Given @A. Chiesa's response, I wrote a short thing to try to make sense of things. Perhaps that document says it best? Thanks again.