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:

  1. var myName = "Kyle";
  2. 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:

  1. let myName = "Kyle";
  2. 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:

  1. var adult = true;
  2. if (adult) {
  3. var myName = "Kyle";
  4. let age = 39;
  5. console.log("Shhh, this is a secret!");
  6. }
  7. console.log(myName);
  8. // Kyle
  9. console.log(age);
  10. // 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:

  1. const myBirthday = true;
  2. let age = 39;
  3. if (myBirthday) {
  4. age = age + 1; // OK!
  5. myBirthday = false; // Error!
  6. }

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:

  1. const actors = [
  2. "Morgan Freeman", "Jennifer Aniston"
  3. ];
  4. actors[2] = "Tom Cruise"; // OK :(
  5. 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:

  1. function hello(myName) {
  2. console.log(`Hello, ${ myName }.`);
  3. }
  4. hello("Kyle");
  5. // 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:

  1. try {
  2. someError();
  3. }
  4. catch (err) {
  5. console.log(err);
  6. }

The err is a block-scoped variable that exists only inside the catch clause, as if it had been declared with let.