The Differences
var
- The scope of βvarβ is limited to the βfunctionβ in which it's defined. If it's defined outside of any function, the scope of the variable is global scope.
- Lexical Scope: Function
- Can be re-assigned
-
Initialization:
undefined
let
- The scope of βletβ is limited to the βblockβ defined by curly braces.
- Lexical Scope: Block
- Can be re-assigned
- Initialization: none
const
- The scope of βconstβ is the same as "let". Additionally, a variable defined with const can't be re-assigned.
- Lexical Scope: Block
- Cannot be re-assigned (can be mutated )
- Initialization: none
Variable Declarations
You can intentionally declare your variables within a specific scope.
We can do it within global scope:
var x
console.log(x) // undefined
// (When a `var` gets declared without a value, it defaults to `undefined`)
We can do it within function scope:
function marco() {
var x
console.log(x)
}
marco() // undefined
And we can do it within block scope:
function marco() {
if (true) {
var x
console.log(x)
}
}
marco() // undefined
If we declare var x
in both the global scope and a function's scope, everything is fine.
var x = "outside"
function marco() {
var x = "inside"
console.log(x) // "inside"
}
marco()
console.log(x) // "outside"
But what if we change the var x
declaration inside the function into a re-assignment?
var x = "outside"
function marco() {
x = "inside"
console.log(x) // "inside"
}
marco()
console.log(x) // "inside"
oops.
var x
outside of the function will get overwritten by the re-assignment inside the function if we remove var
from the inside variable. We need to specify that x
is supposed to be scoped only in function marco()
, or else this will happen.
Function Scope
In JavaScript, you limit the scope of a variable by defining it within a function. This is called function scope.
function marco() {
var text = "it works"
console.log(text) // "it works"
}
marco()
console.log(text) // nothing π€·ββ
Since var
is function scope, it only respects its scope when it's within a function. So that means the following will also work:
function marco() {
var text = "it works"
if (true) {
var text = "no it doesn't"
}
console.log(text) // no it doesn't
}
marco()
Thats no good.
I created an if
statement inside the function, added a var
with the same name as the previous one and accidentally re-assigned its value. An obvious solution would be to use a different variable name, but lets use a better solution to avoid this situation all-together.
Block Scope
Unlike var, let & const are block scoped.
That means as long as the variable is created within a set of curly braces, it's scope will be limited to the block of code within those curly braces. This applies to functions, for loops, if statements, switch statements, and so on.
function marco() {
let text = "it works"
if (true) {
let text = "let is neat!"
console.log(text) // let is neat!
}
console.log(text) // it works
}
marco()
Hey, thats pretty good. We can create multiple variables within a function block without any issues. No accidental re-assignments, no confusion. You should still practice proper naming conventions though. Try not to name two variables the same name if they're in the same function scope.
Thou Shall Not Re-Assign
const will not let you re-assign variables.
const marco = "polo"
marco = "solo" // Hey, thats illegal
It isn't entirely immutable though. You can mutate variables declared with const
.
Array Mutation
const arr = [1]
arr.push(2)
console.log(arr) // [1, 2]
Object Mutation
const obj = {
saying: "marco",
}
obj.saying = "polo"
console.log(obj.saying) // polo
Let & Const Hoisting
All three types of variables (var, let and const) are hoisted. Hoisting means that variables are moved to the top of their scope before the code executes.
Note: All variables are "hoisted"
Unlike var
, let
and const
declarations are not initialized to anything.
var
is initialized to undefined
.
console.log(a) // undefined
console.log(b) // Error: That's Illegal
var a = 0
let b = 0
Note how the logs do not output what were inside the variables we declared. Heres how the interpreter executed it:
var a
let b
console.log(a) // undefined
console.log(b) // Error: That's Illegal
a = 0
b = 0
The interpreter hoisted the variable declarations to the top of the scope, but the variable was not assigned to 0
yet until the interpreter got to that point.
Using let
and const
are nice because if you get into a situation where you call a variable before you declared it, you would get a clear Uncaught ReferenceError: b is not defined
, instead of a silent undefined
.
Stay Hungry, Stay Foolish π
Top comments (8)
That was helpful. Var is really confusing compared to let and const.
let and const behaves exactly like C/C++ variables.
Yep! If you wanna take it even further, you can use TypeScript and add types to make your variables more clear and concise π
Loved this one! Thank you!
Iβm glad you liked it ππ
Thank you! I'm very green and this helped me out alot.
Great post Travis. Didn't know about Hoisting.
I'm glad that it was helpful π
Clears up so much! Thank you!