Variables and scoping in JavaScript are so much more detailed and interesting than we think. This post is about the nitty-gritty and a little advanced stuff regarding variables and scoping in JavaScript. In this post, I will try to elaborate on variable types, accessing and modifying a variable, types of scope and scope chain in JavaScript.
Types Of Scope
In JavaScript, there are mainly three types of scope - global scope, function scope and block scope. Variables declared in the global scope can be accessed anywhere in the program. Variable declared in a function scope can be accessed anywhere in the function body and variable which belong to a block scope can be accessed or modified in that block only (set of curly braces { }). Here's an example -
const firstName = "Christopher";
function getFullName(){
let lastName = "Nolan"
if(lastName){
return firstName + " " + lastName;
}else{
const defaultLastName = "Columbus"
return firstName + " " + defaultLastName;
}
}
In this example, firstName
belongs to the global scope as it is not contained inside any function or curly braces block. lastName
belongs to the scope of getFullName()
function and it can be accessed anywhere inside this function body only. And the accessibility of defaultLastName
is limited to the else
block only. It cannot be accessed anywhere outside the else
block.
Scope Chain
Sometimes, there is a lot of nesting of code and there are lots of blocks present all around and it may be difficult to understand whether we have access to a particular variable or not. In such cases, scope chain can be helpful to resolve issues. For the example code given above, the scope chain will look something like this -
Each Colored reactangle represents a scope and every scope will have access to variables defined in a scope above it. Neither side, nor below. Only above. Scope chain can only look above 👀
After understanding types of scope and scope chain, I think now its a good time to introduce different ways of declaring variables in JavaScript and how they differ from each other.
Declaring variables in JavaScript
There are three main ways of declaring variables in JavaScript - let
, const
and var
(legacy, its use is not encouraged).
Here are some quick points for each way of declaring variable -
let
andconst
are block scoped.var
is function scoped.- Once assigned a value to a
const
variable, it cannot be changed or re-assigned. - We can re-assign a value to
let
andconst
. - We can leave
var
andlet
uninitialized but we cannot leaveconst
uninitialized.
Among these points, the first two are particularly interesting. Lets examine with an example by modifying the code we have been using so far. I am a bit lazy to write new code 😅
const firstName = "Christopher";
function getFullName(){
let lastName = "Nolan";
let fullName;
if(lastName){
var profession = "Director";
fullName = firstName + " " + lastName;
}else{
const defaultLastName = "Columbus";
var profession = "Explorer";
fullName = firstName + " " + defaultLastName;
}
console.log(profession); // logs "Director" when lastName is defined else logs "Explorer"
return fullName;
}
// console.log(profession); Error ⚠️
So as you can see in the code above, we have defined profession
variable for the first time in the if block, then re-declared it in the else block and finally, we accessed it outside the if-else blocks. And still, it logged an appropriate value. It is because var is function scoped. So, even though profession
has been declared first in the if block, it actually belongs to the getFullName()
scope and hence, we were able to access it outside the if-else blocks, that is in the function body.
The scope chain for this example will look something like this -
Hoisting
Because we have talked about variable scopes, so we should talk a little about hoisting as well. Hoisting is a behavior in JavaScript due to which we can access certain things before they are declared. Lets take an example -
console.log(x); // Error - trying to access before declaring
let x = 10;
getValue(); // No error - because functions are hoisted
function getValue(){
console.log(10);
}
getValueAgain(); // Error - no longer hoisted
const getValueAgain = function(){
console.log(10);
}
Gist of the code - A function is hoisted only if it not assigned to a variable.
So that's pretty much it for this blog. Hope you found it helpful!