“Writing in ECMAScript language without understanding closure is like writing Java without understanding classes” — Douglas Crockford, father of JSON
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:
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.
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:
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:
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:
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:
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.
Top comments (0)