Have you ever wondered why your JavaScript code sometimes throws a reference error that a particular variable is undefined, even when you are certain you defined it? Understanding scoping can help unravel this mystery and ensure more efficient coding practices.
By the end of this article, you would be able to :
Know why this error occurs.
Know how to fix this error.
WHAT IS SCOPING?
Scoping refers to how a program's variables are arranged and accessed. It asks questions such as:
Where do variables live?
Where can a variable be accessed from?
In javascript, variables live wherever they are defined. This place is technically called a scope.
Scope refers to the area in which a variable is defined. JavaScript has three major scopes, which are:
Global
Function
Block
A variable is said to be in a global scope when it's not defined in a function or a block. Consider the code below:
let x=2
The x
variable in the code above is in the global scope because it wasn't defined inside any function or block.
However, a variable is said to be in a function scope if it was defined inside a function. Consider the example code below:
function printName(){
const name='John'
return name
}
The name
variable in the code above is an example of a function scope variable. This is because it was defined in the printName
function.
If a variable is defined inside a block of code, the variable is said to have a block scope. A possible example is given below:
function printNum(){
if(true){
let x=5
console.log(x)
}
}
The x
variable in the code above is a block scope variable. This is because it was defined inside the if
block.
Variables defined in the global scope can be accessed by any part of the program. Consider the function below:
let x=10
function printNum(){
console.log(x)
}
printNum()
//10
When you run this code on your local machine, it should print out 10. The printNum
function had access to x
even though it wasn't defined inside the function. This is because any variable defined in the global scope is available everywhere in the program.
However, variables with function or block scope can only be accessed within the function or block in which they were defined. Rewrite the printNum
function from the previous example in the manner below:
function printNum(){
let x=10
console.log(x)
}
printNum()
//10
When you call the printNum
function, note that we have the same result as before.
function printNum(){
let x=10
}
printNum()
console.log(x)
//Uncaught ReferenceError: x is not defined
However, when the console.log(x)
statement was brought outside the function, a reference error was thrown. This is because x
is not defined in the global scope.
Consider the printNum
function from before:
function printNum(){
if(true){
let x=5
console.log(x)
}
}
printNum()
//5
When the function is called, 5 is printed onto the console.
Now, try bringing the console.log()
statement outside the block, what do you notice?
function printNum(){
if(true){
let x=5
}
console.log(x)
}
printNum()
// Uncaught ReferenceError: x is not defined at printNum
This could be a little weird and confusing because x
was defined inside the function. However, the key is to realize that x
was defined inside the if
block, therefore, it was only accessible within that block.
However, there are two major exceptions for how function scope and block scope variables can be accessed:
Variables defined inside a function can be accessed outside the function in certain circumstances.
This occurs when the block the variable is being accessed from is a child of the function.
Consider the code below:
function outer() {
var x = 10;
function inner() {
var y = 20;
console.log(x + y); // Accessible: x from outer scope, y from inner scope
}
inner();
}
outer();
Note that x
was accessible inside the inner
function even though it wasn't defined there. This is because the inner
function is a child of the outer
function where x
is defined.
Variables defined inside a block can be accessed outside the block when using the var keyword.
Consider the
printNum
function again:function printNum(){ if(true){ var x=5 } console.log(x) } printNum() //5
Note that the previous error is not thrown even though we are trying to access x
from outside its "block".
This is because the var
keyword is not block scoped, rather, it takes the scope of the nearest parent function. In reality, x
in the code above has a function scope, not a block scope.
To summarise all, the following points must be noted:
JavaScript has three scopes; global, function, and block scope.
Variables defined in the global scope are accessible everywhere in the program.
Variables defined inside a function can only be accessed outside the function if the place of access is a child of the function.
Variables defined inside a block can only be accessed outside the block if they are initialized with var
keyword.
I really hope this helps clarify some confusion and helps you in writing more efficient codes.