Learnitweb

Scope in JavaScript

1. Introduction

The scope is a general concept in the field of computer science that refers to the parts of the program where a particular variable, function, etc., can be accessed. In other words, the scope of an identifier (variable, function, etc.) is the part of a program where it is visible or can be referenced.

Modern JavaScript has four main types of scopes that are mentioned below:

  • Global Scope
  • Function Scope
  • Block Scope
  • Module Scope

Before discussing the above mentioned scopes, let us discuss the Lexical Scope.

2. Lexical Scope

In JavaScript, the scope of various identifiers (such as variables and functions) is established during compile time.

During this phase, JavaScript engines analyze the structure of the code to determine the scope of each identifier declared. As a result, before the JavaScript code begins its step-by-step execution, the scopes of all declarations have already been determined by the engines.
Scopes can be nested within other scopes, with each nested scope having access to the outer or parent scope.

const myName = "John doe";

function hello() {
	const greeting = "hello " + myName;
	console.log(greeting);
}

In this example, there are three different declarations:

  • myName variable declaration
  • hello function declaration
  • greeting variable declaration

The scope of these declarations depends on where they are written in the code structure. The myName variable and hello function are both in global scope. The greeting variable declaration is inside the hello function, so its scope is local to the hello function.

This type of scope, which is determined at compile time by analyzing the code structure, is known as lexical scope. Lexical scope is also known as “static” scope.

3. Global Scope

The global scope is the outermost scope that encompasses all other nested scopes within it. Every nested scope can access the global scope. In JavaScript, the global scope is associated with the browser window, or more precisely, a browser window tab. This global scope is accessible in JavaScript through the window object. Variables declared with the var keyword and function declarations made in the global scope are added as properties of the window object.

If a variable is declared with let or const, it wouldn’t have been added as a property on the window object, but it would still be a global variable.

4. Avoid polluting the global scope

You should avoid polluting the global scope. Declaring too many variables in the global scope, especially when unnecessary, is known as “polluting” the global scope.

Excessive global declarations can cause unexpected issues and make the code more difficult to manage. The global scope is the parent scope of all other scopes; as a result, the declarations inside the global scope are visible to all other scopes. This can cause problems like variable name clashes, shadowing, etc. Another aspect of the global scope is that it persists until the application is closed. This means that if we aren’t cautious, variables declared in the global scope can remain in memory, even if they are no longer needed, until the application is terminated. That is why, “Avoid polluting the global scope.”

5. Implicit Globals

Whenever there is an assignment to an undeclared variable, JavaScript will declare that undeclared variable as a global variable.

function square(num) {
	result = num * num;
	console.log(result); // 25
}

square(5);

console.log("implicit global: " + result);

In this example, the result variable is not declared. JavaScript will declare the result as a global variable for you. Note that this behavior is only in non-strict mode.

6. HTML attributes

The value of the id attribute or the name attribute of HTML elements also gets added as a variable in the global scope of JavaScript.

<h1 id="message">Hello World!</h1>

The id of the h1 element above gets added to the global scope as a variable. We can access the h1 element using the message as a variable in JavaScript code. This feature is referred to as Named access on the Window object.

7. Shadowing declarations

Declarations inside a nested scope can “shadow” the declarations with the same name in the outer scope. This is referred to as “shadowing declaration” or simply “shadowing.”

Consider the following code example:

let message = "hello";

function printMessage() {
	const message = "hello world";
	console.log(message); // hello world
}

printMessage();

The variable message inside the function is shadowing the message variable declared in the global scope. Shadowing other declarations is generally discouraged because it can decrease the readability of the code.

8. Function Parameter Scope

There are two types of parameters to the function, “simple” and “non-simple”. If the function parameters are defined in such a way that they use ES2015+ features like Default parameters, Destructuring, or Rest parameters, such parameters are non-simple parameters. If the parameters don’t use such features, they are considered to be simple parameters. If the parameters are simple, they behave like they are declared in the function’s local scope, but if the parameters are non-simple, they are declared in their own scope.

function parameterScope(arr = [0], buff = () => arr) {
	var arr = [1, 2, 3];
	console.log(arr); // [1, 2, 3]
	console.log(buff()); // [0]
}

parameterScope();

In this example, the arr parameter and the arr variable inside the function are two different variables that exist in two different scopes. The arr inside the function shadows the arr parameter, but calling the buff function returns the parameter arr. If the parameter and the local arr were the same variable, the buff function would return [1, 2, 3] instead of the default value of the arr parameter.

Now, remove the var to see the change in the output.

function parameterScope(arr = [0], buff = () => arr) {
	arr = [1, 2, 3];
	console.log(arr); // [1, 2, 3]
	console.log(buff()); // [0]
}

parameterScope();

9. Block Scope

In JavaScript, block scope refers to the area within code blocks, like those created by if statements or loops, where variables declared are only accessible within that specific block. The variables declared with the var keyword have function scope. The let and const are block scoped and are accessible within the specific block.

10. Module Scope

In an ES module, the code operates within its own module scope. This means that any declarations made within the module are confined to that module and are not accessible outside of it unless they are explicitly exported. Top-level declarations in a module are restricted to the module itself and do not belong to the global scope.

11. Scope Chain

Scopes can be nested within one another, forming a sequence of linked scopes. This structure is referred to as a scope chain. Whenever a new scope is established, it is connected to its enclosing scope. This connection forms a chain of scopes, allowing the program to search for identifiers in outer scopes if they are not found in the current one.

When the JavaScript engine encounters an identifier in a specific scope, it begins searching for the variable’s declaration in the parent scope. If the declaration isn’t found there, the engine continues searching through each successive outer (parent) scope up the scope chain. This process continues until the global scope is reached, where the search ends if the declaration isn’t found in any of the scopes.

const message = "World";

function hello() {
	const greeting = "hello " + message;

	function greet() {
		console.log(greeting);
	}

	greet();
}

hello();

Output is “hello World”.

In this example, message is not found in the function scope and is searched in the global scope.

12. Conclusion

In conclusion, understanding scope in JavaScript is fundamental to writing effective and error-free code. Scope determines the accessibility of variables and functions within different parts of your code. By mastering the concepts of global, local, block, and lexical scope, along with the rules that govern variable hoisting, closures, and the this keyword, you can avoid common pitfalls like variable leakage or unintended side effects.

As you continue to practice, keep in mind how scope affects variable visibility and function execution. This knowledge will help you write more maintainable and predictable JavaScript, leading to cleaner, more efficient code. Whether you’re working on small scripts or large-scale applications, a solid grasp of scope is essential for any JavaScript developer.