JavaScript Scopes Unveiled: Unlocking the Secrets of Global, Local, and Block Scopes
I find it easier to understand a technical term when I look it up in the dictionary before starting the topic. In this article, we’ll be following that approach.
Scope
noun
- the extent of the area or subject matter that something deals with or to which it is relevant.
"we widened the scope of our investigation"
That explains quite a bit. Let’s get started with what JavaScript has to say about scopes.
What is scope?
Every variable has an identifier, in other words, the name of the variable. Scope defines where this name/data stored in that variable is accessible. If we compare it with our Oxford definition, we see it means where the identifier is relevant and usable.
We have 3 types of scopes in JavaScript. They are:
Global
Function / local
Block
Let’s dive in.
Global Scope
Anything declared outside of a function may be considered as a global scope for a variable.
var x = 'I am a global variable';
function foo(){
y = 'I am a confusing variable that is accessible in global scope';
}
window.z = 'I am defined on window object in browser; also global';
//defines variable in global context
//is accessible by z
For a browser environment, any variable declared in the global scope is accessible with window.<variable_name>. This is not a recommended practice and you should avoid it.
The tricky part is understanding why ‘y’ is in the global scope.
Go ahead and open your console. Copy the above code and paste it. Type in foo()
to invoke the function. Now type y
in the console. See, how we got back the value? You can also type window.y
and you’ll still be able to access the variable. This happens because we have not declared y
with any keyword (var
, const
or let
). By invoking the function we accidentally spilled the value of y
in the global scope since y is implicitly defined as a global variable by the browser.
Function / local scope
Any variable defined within a function is in a function scope.
function foo(){
var x = 'I am a variable within a function scope.';
console.log(x);//I am a variable within a function scope.
}
console.log(x); //Uncaught ReferenceError: x is not defined
In the below implementation, x
is defined within the if block
. But keep in mind, with var
the keyword, x
is still available outside of the if block
. This is because var
has a function scope by default.
function foo(){
if(true){
var x = 'I am inside if block.';
}
console.log(x); //I am inside if block.
}
Even if you define a variable with var
keyword in the innermost nested block it’ll still be accessible within the nearest opening and closing braces of a function. Read that line again and let that sink in.
Block scope
A starting curly brace and an ending curly brace in JS is a block. In JavaScript, we can define a block-scoped variable using let
and const
. To know more about variable declarations check this article.
Rule of thumb - Whenever you use let
or const
make sure to declare it over the top of the block to avoid uncaught ReferenceError.
function foo(){
if(true){
//This is a Temporal Death Zone for x.
let x = 'Hello world';
}
console.log(x); //Uncaught ReferenceError: x is not defined
}
Module scope
Another scope that is available in ES6 is the module scope. They act as private variables which are only available to the module. By exporting those variables they’ll be accessible to the module that imported them.
export const x = 'This is module scope';
TL;DR
var a = 'I am a global variable';
function foo(){
b = 'I am an implicit global variable. But if strict mode is enabled I will throw an error.';
var c = 'I have a function scope';
let d = 'Me too';
const e = 'Count me in';
if(true){
var f = 'I am function scoped';
let g = 'Not me. I am only available within if block.';
const h = 'Block scoped';
}
}
window.i = 'I am in global scope.';