The information in this article is useful for understanding old scripts.
That’s not how we write new code.
In the very first chapter about variables, we mentioned three ways of variable declaration:
var declaration is similar to
let. Most of the time we can replace
var or vice-versa and expect things to work:
var is a very different beast, that originates from very old times. It’s generally not used in modern scripts, but still lurks in the old ones.
If you don’t plan on meeting such scripts you may even skip this chapter or postpone it.
On the other hand, it’s important to understand differences when migrating old scripts from
let, to avoid odd errors.
Variables, declared with
var, are either function-scoped or global-scoped. They are visible through blocks.
var ignores code blocks, we’ve got a global variable
If we used
let test instead of
var test, then the variable would only be visible inside
The same thing for loops:
var cannot be block- or loop-local:
If a code block is inside a function, then
var becomes a function-level variable:
As we can see,
var pierces through
var is a remnant of that.
If we declare the same variable with
let twice in the same scope, that’s an error:
var, we can redeclare a variable any number of times. If we use
var with an already-declared variable, it’s just ignored:
var declarations are processed when the function starts (or script starts for globals).
In other words,
var variables are defined from the beginning of the function, no matter where the definition is (assuming that the definition is not in the nested function).
So this code:
…Is technically the same as this (moved
var phrase above):
…Or even as this (remember, code blocks are ignored):
People also call such behavior “hoisting” (raising), because all
var are “hoisted” (raised) to the top of the function.
So in the example above,
if (false) branch never executes, but that doesn’t matter. The
var inside it is processed in the beginning of the function, so at the moment of
(*) the variable exists.
Declarations are hoisted, but assignments are not.
That’s best demonstrated with an example:
var phrase = "Hello" has two actions in it:
- Variable declaration
- Variable assignment
The declaration is processed at the start of function execution (“hoisted”), but the assignment always works at the place where it appears. So the code works essentially like this:
var declarations are processed at the function start, we can reference them at any place. But variables are undefined until the assignments.
In both examples above,
alert runs without an error, because the variable
phrase exists. But its value is not yet assigned, so it shows
In the past, as there was only
var, and it has no block-level visibility, programmers invented a way to emulate it. What they did was called “immediately-invoked function expressions” (abbreviated as IIFE).
That’s not something we should use nowadays, but you can find them in old scripts.
An IIFE looks like this:
Here, a Function Expression is created and immediately called. So the code executes right away and has its own private variables.
The Function Expression is wrapped with parenthesis
"function" in the main code, it understands it as the start of a Function Declaration. But a Function Declaration must have a name, so this kind of code will give an error:
In all the above cases we declare a Function Expression and run it immediately. Let’s note again: nowadays there’s no reason to write such code.
There are two main differences of
var compared to
varvariables have no block scope, their visibility is scoped to current function, or global, if declared outside function.
vardeclarations are processed at function start (script start for globals).
There’s one more very minor difference related to the global object, that we’ll cover in the next chapter.
These differences make
var worse than
let most of the time. Block-level variables is such a great thing. That’s why
let was introduced in the standard long ago, and is now a major way (along with
const) to declare a variable.