console
.
log
(
z
);
// logs 3
}
Variable masking is sometimes called variable shadowing (that is, a
variable with the same name will shadow the variable in the outer
scope). I’ve never cared for this term because shadows don’t usually
completely obscure things, just make them darker. When a variable
is masked, the masked variable is completely inaccessible using that
name.
By now, it should be clear that scope is hierarchical: you can enter a new scope
without leaving the old one. This establishes a scope chain that determines what vari‐
ables are in scope: all variables in the current scope chain are in scope, and (as long as
they’re not masked), can be accessed.
Functions, Closures, and Lexical Scope
So far, we’ve only been dealing with blocks, which make it simple to see lexical scope,
especially if you indent your blocks. Functions, on the other hand, can be defined in
one place and used in another, meaning you might have to do some hunting to
understand their scope.
In a “traditional” program, all of your functions might be defined in global scope, and
if you avoid referencing global scope in your functions (which I recommend), you
don’t even need to think about what scope your functions have access to.
In modern JavaScript development, however, functions are often defined wherever
they’re needed. They’re assigned to variables or object properties, added to arrays,
passed into other functions, passed out of functions, and sometimes not given a name
at all.
It’s quite common to intentionally define a function in a specific scope so that it
explicitly has access to that scope. This is usually called a closure (you can think of
closing the scope around the function). Let’s look at an example of a closure:
let
globalFunc
;
// undefined global function
{
let
blockVar
=
'a'
;
// block-scoped variable
globalFunc
=
function
() {
console
.
log
(
blockVar
);
}
}
globalFunc
();
// logs "a"
globalFunc
is assigned a value within a block: that block (and its parent scope, the
global scope) form a closure. No matter where you call
globalFunc
from, it will have
access to the identifiers in that closure.
Functions, Closures, and Lexical Scope | 123