Declaring and Using Variables
To be explicit about something that may not have been obvious in the previous section: in JS programs, values can either appear as literal values (as many of the preceding examples illustrate), or they can be held in variables; think of variables as just containers for values.
Variables have to be declared (created) to be used. There are various syntax forms that declare variables (aka, “identifiers”), and each form has different implied behaviors.
For example, consider the var
statement:
var myName = "Kyle";
var age;
The var
keyword declares a variable to be used in that part of the program, and optionally allows an initial assignment of a value.
Another similar keyword is let
:
let myName = "Kyle";
let age;
The let
keyword has some differences to var
, with the most obvious being that let
allows a more limited access to the variable than var
. This is called “block scoping” as opposed to regular or function scoping.
Consider:
var adult = true;
if (adult) {
var myName = "Kyle";
let age = 39;
console.log("Shhh, this is a secret!");
}
console.log(myName);
// Kyle
console.log(age);
// Error!
The attempt to access age
outside of the if
statement results in an error, because age
was block-scoped to the if
, whereas myName
was not.
Block-scoping is very useful for limiting how widespread variable declarations are in our programs, which helps prevent accidental overlap of their names.
But var
is still useful in that it communicates “this variable will be seen by a wider scope (of the whole function)”. Both declaration forms can be appropriate in any given part of a program, depending on the circumstances.
NOTE: |
---|
It’s very common to suggest that var should be avoided in favor of let (or const !), generally because of perceived confusion over how the scoping behavior of var has worked since the beginning of JS. I believe this to be overly restrictive advice and ultimately unhelpful. It’s assuming you are unable to learn and use a feature properly in combination with other features. I believe you can and should learn any features available, and use them where appropriate! |
A third declaration form is const
. It’s like let
but has an additional limitation that it must be given a value at the moment it’s declared, and cannot be re-assigned a different value later.
Consider:
const myBirthday = true;
let age = 39;
if (myBirthday) {
age = age + 1; // OK!
myBirthday = false; // Error!
}
The myBirthday
constant is not allowed to be re-assigned.
const
declared variables are not “unchangeable”, they just cannot be re-assigned. It’s ill-advised to use const
with object values, because those values can still be changed even though the variable can’t be re-assigned. This leads to potential confusion down the line, so I think it’s wise to avoid situations like:
const actors = [
"Morgan Freeman", "Jennifer Aniston"
];
actors[2] = "Tom Cruise"; // OK :(
actors = []; // Error!
The best semantic use of a const
is when you have a simple primitive value that you want to give a useful name to, such as using myBirthday
instead of true
. This makes programs easier to read.
TIP: |
---|
If you stick to using const only with primitive values, you avoid any confusion of re-assignment (not allowed) vs. mutation (allowed)! That’s the safest and best way to use const . |
Besides var
/ let
/ const
, there are other syntactic forms that declare identifiers (variables) in various scopes. For example:
function hello(myName) {
console.log(`Hello, ${ myName }.`);
}
hello("Kyle");
// Hello, Kyle.
The identifier hello
is created in the outer scope, and it’s also automatically associated so that it references the function. But the named parameter myName
is created only inside the function, and thus is only accessible inside that function’s scope. hello
and myName
generally behave as var
-declared.
Another syntax that declares a variable is a catch
clause:
try {
someError();
}
catch (err) {
console.log(err);
}
The err
is a block-scoped variable that exists only inside the catch
clause, as if it had been declared with let
.