Page 2: Variables and Scope
JavaScript Variables
Javascript has 3 main ways to declare variables: let
, const
, and var
.
var
is the old way to declare variables. Don’t use it. It creates variables that object confusing rules. The lexical scoping rules discussed here do not apply. var
is one of those legacies of the “bad old days” when JavaScript was a poorly designed language. Just don’t use var
.
Technically, function
canm also be used to declare variables. But think about
function foo(arg) { /* some code between the braces */ }
const foo = function (arg) { /* some code between the braces */ };
Both const
and let
declare variables using the “modern rules.” They are what we should
use in our JavaScript programs.
Lexical Block Scope
The Scope of a variable is the range of the program where the variable can be “seen”.
For const
and let
variables in JavaScript, the basic rules are fairly simple:
- Variables can only be seen after they have been declared.
- Variables can only be seen inside the block where they are declared. (a block is more or less a set of curly braces)
You are probably used to this. It is the way most other programming languages work. For example…
|
|
Based on Javascript’s rules, we can use x
on line 5, but not on 7, or 3, or 1. The scope of variable x
is from where it is declared until the close brace (}
) that ends the block it is declared in.
That might seem so simple that I shouldn’t have bothered to say it, but I want to be explicit about the notion of scope, because it can get more complicated. However, it isn’t too complicated: we can always figure out the cope of a variable by reading the program. The variable is only in scope between where it is declared and the close brace.
The complexity comes in because blocks nest - we can have blocks inside of blocks. Here’s another toy example:
|
|
This example is only slightly trickier.
Notice that on line 3, we are in a new block, but a
remains in scope.
Similarly, on line 6 we start a new block, but the things that were in scope
remain in scope.
However, when we declare c
in this inner block, its scope ends when the inner
block ends (on line 10).
Of course, we can re-use variable names. So here’s a classic programming test question, what number does this program print?
|
|
You should be able to figure out that it prints 1. The variable a
inside the f
function is the one defined on line 4. The variable a
on line 9 is the one defined on line 7. When g
is called, it executes line 9 (setting the a
variable on line 7 to the value 2), and it then calls the f
function that changes the a
variable on line 1.
Of course, this can be even trickier since we can define functions inside of functions.
|
|
a
on line 4 is in scope from lines 4 to 6. The a
on line 8 comes from its enclosing block (the a
on line 2). Similarly, the a
on line 12 is the a
from line 2.
These examples didn’t consider arguments. But basically, function arguments are the same as variables declared right at the beginning of the block.
Next, we’ll see how this leads to closures.
Next: Closure