Let vs Var vs Const
In this tutorial blog I will try to explain difference between let, var & const. I'll also briefly cover variable hosting. Hope you find this tutorial useful.
**
Var
**
When a var variable is declared outside a function, it’s said to be globally available. This means that it’s globally scoped, or available to the entire window. Scope asks: where in our code can our variables be used?
But when we declare a var variable inside a function, that variable is no longer globally scoped; instead, it’s locally scoped.
var hello = "hello"
function greeting() {
var goodbye = "goodbye"
}
console.log(hello) // "hello"
console.log(goodbye) // ReferenceError: goodbye is not defined
This error is telling us that goodbye doesn’t exist, or at least it’s not accessible from the window. That’s because it has functional scope and can’t be accessed from outside that function. I like to think that the curly braces are “hiding” this variable from the outside environment.
What happens when we declare the same var variables globally and locally?
var name = "Jamie"
function greeting() {
var name = "Adam"
return `Hi, ${name}!`
}
greeting() // "Hi, Adam!"
We can see that invoking greeting returns the locally scoped var variable. This is due to JavaScript’s scope chain: JavaScript will first look for a matching variable in a function’s local scope before it checks the global scope. Scope chain is uni-directional and always starts with the nearest local scope before moving outward.
Another important note about var variables is their ability to overwrite a previously declared var variable in the same scope:
var weather = "rainy"
var weather = "sunny"
console.log(weather) // "sunny"
You can probably agree that this isn’t always favorable. When we write lengthy code, we may unknowingly redeclare the same variable more than once because it happens to the best of us. Hence, why ES2016 introduced let and const.
**
Hoisting of var
**
Hoisting is a metaphor for describing the behavior of a variable “binding” to its lexical scope when the interpreter first runs through our code line by line. Var variables are initialized a value of undefined during this “read-only” phase.
console.log(snack) // snack is undefined
var snack = "frozen yogurt"
// the above code is interpreted as:
var snack // this is the important part
console.log(snack) // snack is undefined
snack = "frozen yogurt"
It’s important to know that not defined and undefined aren’t the same thing: not defined suggests that the variable doesn’t exist at all whilst undefined means that your interpreter allocated memory for this variable but no value was assigned to it yet.
**
Let
**
When we use a let variable within a code block, it’s available only within that code block (block scoped). A code block is anything between {}. This means that if/else statements and for loops are code blocks. You’ll soon see that var doesn’t behave the same way.
Declaring a let variable in the global scope will make it available to all functions declared in that scope.
let snack = "sundae"
function newFunction() {
console.log(snack)
}
newFunction() // "sundae", undefined
Like var, a let variable and its value can be updated in the same scope. However, we can’t redeclare a let variable.
let snack = "sundae"
let snack = "cheese cake"
// SyntaxError: Identifier "snack" has already been declared
let snack = "sundae"
snack = "cheese cake"
// no error!
The difference between var and let is clear when we look at non-function code blocks such as if/else statements. Declaring the same let variable in the global scope and within a code block won’t throw an error; each variable keeps its assignment as declared in its scope.
let genre = "fiction"
if (true) {
let genre = "mystery"
console.log(genre) // "mystery"
}
console.log(genre) // "fiction"
But var variables, which are function-scoped, will cause reassignment in the same example: var genre = "fiction"
if (true) {
var genre = "mystery"
console.log(genre) // "mystery"
}
console.log(genre) // "mystery" <-- reassigned value
**
Hoisting of let
**
Like var, let variables are hoisted to the top of its scope. However, unlike var, calling a let variable before declaring and assigning it will throw a not defined error. So, let variables are hoisted but not initialized. This just means that let variables are not given a value of undefined. This is known as the temporal dead zone. Let variables are not initialized until the actual declaration is executed.
console.log(greeting) // ReferenceError: greeting is not defined
let greeting = "goodbye"
However, we can get an output of undefined if we declare our variables like this:
let greeting
console.log(greeting) // undefined
greeting = "How are you?"
**
Const
**
Const variables are assigned values that are constant, or don’t change throughout your code. Like let, const variables are available within the scope that they are declared. Additionally, const variables are hoisted to the top of the scope but not initialized. Basically, const and let variables behave exactly the same with few exceptions — const variables cannot update its values; they are immutable.
And one more thing: const variables must be declared and initialized (assigned) in the same line prior to using them. Otherwise, a SyntaxError is thrown.
const API_URL
console.log(API_URL)
// SyntaxError: Missing initializer in const declaration
API_URL = "localhost:3000/"
Const variables are hoisted to the top of their scope like let and var variables.
**
Summary
**
Var:
- function-scoped
- can overwrite a value of another variable with the same name
Let:
- block-scoped
- can update variables within the same scope
Const:
- block-scoped
- variables are immutable