Scope can be said to be a set of rules that indicate where we should look for a variable. It defines the area where variables are available. A variable will normally belong to a certain context of execution. In this context certain variables- values and expressions are "visible" and or can be refered to. Outside of this, there's no access to the variable.
Variable scope
Normally variables in Javascript will either be defined in global or local scope. A variable declared outside a function is global. Otherwise, variables are limited to the local scope of the function in which they are defined.
Global Scope
A variable declared as global lives throughout run-time. It is accessible and alterable in any scope as the global scope is a parent to all scopes in the execution.
//carname is accessible here
var carname="Mercedes Benz";
function car() {
console.log(carname); // Mercedes Benz
//carname is accessible from within here
}
console.log(carname); // Mercedes Benz
//carname is accessible here
Local Scope
While global scope is useful in programming, it's not always good practise. Following the "Principle of Least Privilege" in software design, it's always best to apply scope-hiding techniques. This entails declaring variables nested inside blocks or functions. This creates what we call local scope.
In Javascript, a locally scoped variable is available only within the function wherein it's defined. Variables living here have their scope recreated with every call of the function during runtime. The variables remain inaccessible unless reference is within the local scope of the function.
//carname is not accessible here
function car() {
var carname = 'Mercedes Benz';
//carname is accessible from within here
console.log(carname); // Mercedes Benz
}
//carname is not accessible here
console.log(carname); // ReferenceError: carname is not defined
As you can see the variable carname declared within the function is not reachable from outside the function. Thus a function has it's local scope and variables within it cannot be accessed from outside.
Function Scope
Javascript has lexical scoping with functions. Within lexical scopes, a variable name's scope is restricted to that function, within the function definition. It lives and is bound here, and outside the function it can't be referenced.
It is important to note that curly braces {} in Javascript do not create a new scope. This is because (prior to the ECMA 6 standard) curly braces do not create a new scope. Only through the creation a new function is a new scope created.
Function scope does not exist until a function is called.
//Function scope
var carname = 'Mercedes Benz';
function car(carname) {
console.log(carname);
}
//carname is not accessible here
car('BMW'); // BMW
console.log(carname); // Mercedes Benz
car('Rolls Royce'); // Rolls Royce
console.log(carname); // Mercedes Benz
car('Volvo'); // Volvo
After each time the function car is called a new scope is created and prints out the outputs in the variable carname. Thus each time the function is called a new scope has a different output as seen above BMW, Mercedes Benz. The global variable carname retains it's values all the while.
Block scope
Block scope is just a block of code. Block are executed immediately, as opposed to functions that have to be called. Blocks in Javascript would include if-statements, loops etc. Prior to ECMAScript 6 (ES6/ES2015) Javascript had no block scopes. A block prior to this would have worked as follows.
// Blocks in Javascript don't create scope
var carname="Mercedes Benz";
if (true){
var carname = "Volvo";
console.log(carname); // Volvo
}
console.log(carname); // Volvo
As you can see, carname even when declared within the block still refers to the globally scoped variable of the same name. Any updates within the block affected the globally scoped variable, because in reality, carname within the block still refers to the globally scoped variable of the same name. Evidently no locally scoped variable is created.
Previously, the way to create block scope was by using Immediately Invoked Function Expressions (IIFE) pattern.
//IIFE Demo
var carname = 'Mercedes Benz';
(function car(carname) {
var carname = 'Volvo';
console.log(carname);// Volvo
})()
//carname prints out the global scope value
console.log(carname); // Mercedes Benz
The output of carname within the function is changed within the function expression, without affecting global variable carname.
ECMAScript 6 (ES6/ES2015) introduced light-weight blocks using the let and const keywords. These can be used to create a new local scope within the block. Thus access to a variable is confined to the scope of the block in which it's defined. This scope is also only created during runtime anytime the block is executed in the stack and accessibility is only from within the block.
//Block Scope Demo
var carname="Mercedes Benz";
if (true) {
let carname = "Volvo";
let vehiclename = "Volvo";
//vehiclename is only accessible from within here
console.log(carname); //Volvo
}
console.log(carname); //Mercedes Benz
console.log(vehiclename); //Uncaught ReferenceError: vehiclename is not defined
The vehiclename variable is only accessible inside the block scope.
That's it!
We've covered the basics regarding scope in this post. There's always more to learn, but this should be sufficient to help you grasp the basics. Happy coding!
Top comments (0)