DEV Community

Ashutosh Kumar Singh
Ashutosh Kumar Singh

Posted on • Originally published at Medium on

6 2 1

A Brief Introduction to Closures and Lexical Scoping in JavaScript

“Writing in ECMAScript language without understanding closure is like writing Java without understanding classes” — Douglas Crockford, father of JSON

Photo by Caspar Camille Rubin on Unsplash

In this piece, we are going to discuss closures and lexical scoping in JavaScript. Understanding closures leads to a better understanding of programming itself. If you are planning on becoming a professional programmer, questions regarding closures and their applications are widely asked during technical interviews and can be really helpful to you.

If you are a JavaScript Developer, chances are you already using closures and just don't know it. There are so many complex examples out there that just confuse you when you try to learn closures, so I’ll be using the simplest examples I could find and by the end of this piece, you should have a basic understanding of what closures are. Let's get started.

Lexical Scoping

Before we can discuss closures, we should have a basic understanding of the scope and lexical scope. JavaScript has lexical scoping with function scope, which means each function creates a new scope.

What is function scope?

Basically, in JavaScript, there is Global Scope and Local Scope.

Global Scope : There is only one Global Scope in a Javascript Document i.e. area outside all the functions and how you can identify a global scope is that the variable defined in the global scope can be accessed anywhere in the code.

Local Scope : Variables declared inside functions are local to the function and is bound to the corresponding local scope. Those variables cannot be accessed outside the functions.

Let's see an example:

// global scope
let iHaveGlobalScope=`I can be accessed from anywhere in this document`
function localScope()
{
console.log(iHaveGlobalScope)
// lcoal scope1
let iHaveLocalScope=`I am bound to the local scope of function localScope`
}
console.log(localScope())
//I can be accessed from anywhere in this document
console.log(iHaveLocalScope)
//ReferenceError: iHaveLocalScope is not defined
view raw scope1.js hosted with ❤ by GitHub

The variable iHaveGlobalScope is declared in the global scope and therefore can be accessed even from within the function localScope(), but when I try to console log the variable iHaveLocalScope outside the function or outside the local scope, it throws a Reference Error at runtime.

The local scope can be further divided into function scope and block scope. The concept of block scope was introduced in ES6 together with the new ways to declare variables — const and let.

Function Scope and Block Scope

Whenever you declare a variable inside a function, the variable is bound within the function and you can’t access it outside the function. var is the keyword to define a variable for function-scope accessibility.

function functionScope(){
var iHaveFunctionScope=`something something mj`
console.log(iHaveFunctionScope)
}
functionScope()
//something something mj
console.log(iHaveFunctionScope);
//Reference Error
view raw scope2.js hosted with ❤ by GitHub

Now, you might ask, if it gives an error even if you use let or const, why is only var associated with function scope? The thing is, let and const are used to define block scope, and before ES6, JavaScript didn't have block scope or let and const.

A block scope is the area within if, switch conditions or for and while loops. Simply put , whenever you see {curly brackets}, it is a block.

Let's see an example:

function scope(){
if(true){
var scope1 =`I have function Scope`
let scope2 = `I have block scope`
const scope3 =`I also have block scope`
}
console.log(scope1)
console.log(scope2)
console.log(scope3)
}
scope()
//I have function Scope
//ReferenceError: scope2 is not defined
//ReferenceError: scope3 is not defined
view raw scope3.js hosted with ❤ by GitHub

Now you might expect that none of the log commands should work but as you can see that is not the case with var, variables defined with var inside if, switch conditions or for and while loops can be accessed globally and are part of global scope and hence it is better practice to use let and const with them.

Lexical Scope

Finally, we have reached the true purpose of this post. Well, I could have skipped the long discussion of scope but personally, I don’t think you can understand lexical scope without knowing the key components revolving around it.

Again, a point to remember: Javascript has lexical scoping with functions scope.

In simple words, it means the children scope has access to the variables defined in the parent scope. For instance, If I were to define a function and declare a variable inside it and inside the very same function, define another function, then I should be able to use that variable inside the inner function because of lexical scoping. Let's see an example:

function outerFunction() {
var variable1 = 'ney vatsa'
const variable2 = 'shashank jha'
let variable3 = 'huda'
function innerFunction() {
console.log(variable1)
console.log(variable2)
console.log(variable3)
}
innerFunction()
}
outerFunction()
// ney vatsa
//shashank jha
//huda
view raw scope4.js hosted with ❤ by GitHub

It can be seen from the example, the variables declared in outerFunction() are accessed by innerfunction(), this is lexical scoping.

The scope of variables is defined by their position in the code. In order to resolve variables, JavaScript starts at the innermost scope and searches outwards until it finds the variable it was looking for. In the above example, Javascript first searches for variables inside innerFunction() and when it doesn’t find it, it goes outside i.e outerFunction()

Lexical scoping is better because we can easily figure out the value of a variable from the code, whereas in dynamic scoping, the meaning of a variable can change at runtime, which makes it complex to understand.

So, we have successfully understood what lexical scoping is, now let’s look at closures where lexical scoping is actually used.

Closures

According to the Mozilla Development Network(MDN) :

“A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created.”

First, let's look at a simple example to start:

var outerFunction = function () {
let variable1 = "Example of closure"
var innerFunction = function () {
console.log(variable1)
}
return innerFunction;
}
var newFunction = outerFunction()
newFunction()
//Example of closure
view raw scope.js hosted with ❤ by GitHub

The main point to think here is outerFunction() returns innerFunction() , so the newFunction() is in fact innerFunction(), but we didn’t return variable1. Still, it is a part of newFunction(), so where does the value of variable1 comes from if outerFunction() is already returned i.e. finished executing.

This accessing of a variable outside the immediate scope will give rise to a closure.

Since variable1 was part of the lexical environment that created innerFunction(), innerFunction() will have access to it.

Let's look at another example:

function add(x) {
return function(y) {
return x + y;
};
}
var addFive = add(5);
var addTen = add(10);
console.log(addFive(10)); // 15
console.log(addTen(10)); // 20
view raw scope6.js hosted with ❤ by GitHub

Just FYI, this is a widely used example for closure and you may find it many tutorials, here we have defined the function add() with a parameter x which returns another function with parameter y, which returns the sum of x and y.

Now we create new functions addFive() and addTen(), by passing arguments inside add() function, these addTen() and addFive() are actually closures, and although they have the same function body definition, they store different lexical environments. In addFive() lexical environment, x is five, while in the lexical environment for addTen(), x is ten.

Closures are a very important part of programming, not only in JavaScript but in all programming languages. They have so many practical applications like object data privacy, event handlers and callback functions, and other functional programming patterns.

I hope by now you have a basic understanding of scope in JavaScript, we have covered a brief introduction to lexical scoping and closures in this post. in next post, we will discuss the closures in detail and its actual use like data privacy, call(), bind(), apply(), event handlers, etc. through various examples.


AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

nextjs tutorial video

Youtube Tutorial Series 📺

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series 👀

Watch the Youtube series

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay