2

Understanding JavaScript Closures: Scope Chain and Emulating Private Methods wit...

 2 years ago
source link: https://hackernoon.com/understanding-javascript-closures-scope-chain-and-emulating-private-methods-with-closures
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Understanding JavaScript Closures: Scope Chain and Emulating Private Methods with Closures

Closures are one of the most asked interview questions in JavaScript and a lot of people who have worked with JavaScript for a while also don’t understand closures. So, knowing closure is very important as a JavaScript developer. To prepare you for your next big interview, I have put together this curated article, dissected to help broaden your horizons and understanding of JavaScript closures in depth.  
Queen Nnakwue

Queen Nnakwue is a software engineer et technical writer based in Lagos, Nigeria.

Quick Summary

Closures are one of the most asked interview questions in JavaScript and a lot of people who have worked with JavaScript for a while also don’t understand closures. So, knowing closure is very important as a JavaScript developer. To prepare you for your next big interview, I have put together this curated article, dissected to help broaden your horizons and understanding of JavaScript closures in depth.  

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Introduction

Understanding closures and how they work can reveal so much about how we work with JavaScript and other programming languages like C# and Python since they all rely on this concept. In JavaScript, closures are not a new construct, but they are a concept that is used to describe what is possible within JavaScript and, understanding it opens up possibilities for you that you may not have thought of in the past. Also, it helps you understand the JavaScript code that is being written out there.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

This indeed explains why so much emphasis is placed on the need to understand closures. In this article, we will be introducing JavaScript Closures from the ground up. We will start by looking at closures from a high level - what are they, how they work, how to use them in our code, and how they are structured.  We will also take a look at the scope chain and its use cases. Additionally, we will explore how to emulate private methods with closures. A basic understanding of the JavaScript function scope and familiarity with the lexical environment is necessary to follow through with this tutorial.  On the flip side, we will also get to cover these basics, so readers of all background levels can follow suit.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

What Is Closure?

A Closure is a function (an inner function) that has access to another function (an outside function) outside of its scope. It is a function combination created by calling a function inside another function.  

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Quoting Kyle Simpson, Closure is when a function is able to remember and access its lexical scope even when that function is executed outside its lexical scope. One common feature peculiar to these definitions is that a code can execute outside of scope and yet still have access to "that scope". 

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Closure is a widely used concept not only in JavaScript but also in Nodes’ single-threaded, event-driven, and non-blocking architecture. 

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Let’s take a look at a basic example:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
function greeting(){
    let message = "Hello World";
    function displayMessage(){
    alert(message);
}
     return displayMessage
}
     let newMessage = greeting();
     newMessage();

In the above example, greeting() creates a local variable called message and an inner function called displayMessage(), defined inside greeting() and is available only within the scope of the greeting() function. But, it will interest you to note that displayMessage() can access the variable message declared in its parent function, greeting()

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Let’s try this in real-time. Go to your dev tools in your browser and run the above lines of code. Notice that “Hello World” is passed to alert? The reason isn’t far-fetched. Recall that we mentioned at the beginning that closures are a combination of functions that have access to each other within the same lexical environment. Following that definition, newMessage is a reference to the instance of the function displayMessage that is created when the greeting() function is run.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Note: The instance of displayMessage keeps a reference to its lexical environment, within which the variable message exists. 

0 reactions
heart.png
light.png
money.png
thumbs-down.png

For this reason, when newMessage is invoked, the variable message remains available for use, and "Hello World" is passed to the alert.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Using closures in your code

To reiterate further, one of the most important features of closures is that the inner function still has access to and is able to use the outer function’s variables even after the outer function has run or returned. 

0 reactions
heart.png
light.png
money.png
thumbs-down.png

In JavaScript, functions execute using the same scope chain that was in place when they were created. What this means is that the inner function has access to the outer function’s variables even after the outer function has returned.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

 In this section, we will look at three different ways we can implement closures in our program/code.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Example 1: In this first example, we will assign a var me the value James and declare a function called greetMe which console logs (‘Hello, ‘ + me + ‘!’) and then we call the greetMe function like so:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
var me = 'James';
function greetMe() {  
console.log('Hello, ' + me + '!');
}
greetMe(); //This outputs 'Hello, James!' when called

Notice in line 5 that we did not pass any arguments in our greetMe function. That is, we called our function without any argument. What this means is that we are referring to me in line 1 that is assigned outside of the function scope. The reason that we can do this is that JavaScript functions like greetMe are closures. We cannot do this in languages that do not have support for closures. For languages without support for closures, we would pass the name James as an argument to the function greetMe in line 5. This is because such a language does not have access to the outer scope of itself.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

I would like to stress here that greetMe does have access to the outer variable scope. It does not snapshot the value of me at the time it is declared. For instance, if I reassigned me to be Matt , what gets outputted will be: Hello, Matt! like so:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
var me = 'James';
function greetMe() {  
console.log('Hello, ' + me + '!');
}
me = 'Matt';
greetMe(); //This outputs 'Hello, Matt!' when called

What this tells you is that greetMe does not copy the value of me, instead it reads whatever the value of me is at that time from the outer scope, and it will do this even if greetMe was an asynchronous function being called from an AJAX callback or something like that. The function greetMe will remember this outer context that it declares even if greetMe is called from a completely different part of the application or a different module, it will still refer to this specific context in line 1.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Example 2:

0 reactions
heart.png
light.png
money.png
thumbs-down.png

In this second example, we will define an inner function, firstName (outer function) and another function lastName(a closure) inside our firstName function and show you how our lastName function (inner function) still has access to our outer function even after our outer function, firstName has returned.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Let me show you what I mean:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
function firstName (firstName) {  
var Intro = "My name is ";  
// this is an inner function which as we will get to see, has access to the outer function's variables

//this function, lastName is a closure because it is a function inside another function)   
function lastName (lastName) {        
return Intro + firstName + " " + lastName;    
}    
return lastName;
}
var fullName = firstName("Queen");
//The firstName outer function has returned which we passed to this var fullName

fullName ("Nnakwue");  // My name is Queen Nnakwue

// Here, the closure (lastName) is called after the outer function has returned above
// Yet, the closure still has access to the outer function's //variables and parameter

Example 3:

0 reactions
heart.png
light.png
money.png
thumbs-down.png

In this example, we will see how we can use closure to define a function (an inner function) which we will call  n inside another function, which we will call m (an outer function) and expose n

0 reactions
heart.png
light.png
money.png
thumbs-down.png
function multiply (m) {  
return function (n) {   
 return m * n  
};
}
var multiply9 = multiply(9)
var multiply5 = multiply(5)

console.log (multiply9(8)); // 72
console.log (multiply5(12)); // 60

In the code snippet above, we defined a multiply(m) function, which takes a single argument, m, and returns a new function, n. The function it returns, in turn, takes a single argument, n, and returns m  * n. multiply is used to create two new closures (functions) — multiply9  and  multiply5 which although share the same function body definition, have different lexical scopes. For instance, In the lexical scope of multiply9, m is 9 while in multiply5, m is 5. 

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Closure is one of those things in JavaScript that permeates the entire language. It is all around you in JavaScript. You have to use it and embrace it. There are more use cases for closures than the ones I have shown you; more than would fit into this article. Closure is one of those things that you have to use a lot, on your own and in your code, for you to internalize it. However, MDN, has good JavaScript documentation alongside a super good page on closures on their site. You should check out some of the examples there and start using closures in your code to get a feel for them.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Closures in Callbacks

One very common use case where closures are essential is in callbacks. JavaScript has a feature called callback where you can send a function to another function and have that function execute whatever code you have in your function.  

0 reactions
heart.png
light.png
money.png
thumbs-down.png

As you might already know, JavaScript execution is single-threaded. That is, whenever you have a page open in a browser, there is one thread assigned to execute the code that executes on that page, so you don’t really have the option of creating multiple threads. Because it’s single-threaded, the JavaScript language doesn’t have features like wait or pause, but instead, what you have is the setTimeOut feature.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Let’s take a look at a setTimeOut example. So let’s say I want to have like var b = 20 and I want to wait for one second and then console log b like so:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
b = 20;
//wait for one second
console.log(b);

Question: how do I make the browser wait for one second since there is no feature like wait or pause in JavaScript? The way to do this is by using a function called setTimeOut(). The setTimeOut() function comes with JavaScript to enable things like having an execution happen after some time. This function takes two parameters: the first is the function that it needs to execute and the second is the time it needs to wait before executing. Let’s go back to our code and add the following lines of code:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
b = 20;
//wait for one second
var fn = function(){
// the function we want to execute after 1000 milliseconds  console.log(b);
};
setTimeOut(fn, 1000);

From the above snippet, we defined a setTimeOut() function and we passed some arguments to it. The first argument, fn is the function we want it to execute after 1000 milliseconds, which we declared above in line 5 while the second argument, 1000 milliseconds is the time we want it to wait before executing our function. When you console log this on your terminal, you will notice that it waited for a second before outputting 10 on your console.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Again, you might be wondering: What do closures have to do with this? I’ll show you. In line 6, we console log b even when b is nowhere around our setTimeOut function. This is where closures come into play. Let me explain better. When lines 5-7 are executed, it makes a snapshot of all the variables in the scope. So there is var a in the scope which contains a value of 10. It doesn’t matter because it knows this variable here, in line 1, was created at this point. This function object, lines 5-7, then created, knows that there is this variable a in line 1 at this point, in this place in memory and it remembers it in this function itself. What then happens is that when you pass this function a in line 1 at this point, in this place in memory, and it remembers it in this function itself. What then happens is that when you pass this function to setTimeOut, you’re actually also passing information about the scope information and about where this variable a is. This clearly explains how we can use closures in callbacks.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

The Module pattern

Another practical use of closures is in what’s called the module pattern in JavaScript. In JavaScript, there is no concept of private and public methods. You can create functions as properties of objects and then those functions are accessible like any other properties and can be accessed by using a reference. For example, let’s create a person object and inside this object, we have properties, firstName, and lastName. Let’s say I also want to create getters and setters for my firstName and lastName properties and return them both, I can do that by using a couple of more properties called functions. For example, getFirstName and getLastName are both going to be functions. Let’s write some code:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
 var person = {    
"firstName" = "John",   
"lastName" = "Doe",    
"getFirstName" : function(){      
return this.firstName;  
},    
"getLastName" : function(){      
return this.lastName;  
},  
};

To use the getter method from the code above, we can run person.getFirstName() which will return John. Beyond this concept of getter (used to access properties using a function), the concept is also to prevent access to the property itself. In other languages, we can use either private or public methods. Functions/methods created as public are accessible everywhere, while methods/functions created as private are only accessible inside that class. For instance, if we don’t want the two variables in line 2 and 3 to be accessible outside, all we need to do is to create them as private, but this concept is unfortunately not available in JS. 

0 reactions
heart.png
light.png
money.png
thumbs-down.png

This is one use case where the use of closures actually helps. The good news is that we can use closures to make our variables private using a pattern called the ‘module pattern’. The module pattern basically helps you create private data and public APIs. To use closures in our code using the module pattern, we are going to transform our code so that the variables become private and inaccessible from the outside but have methods which work on the variables. We can achieve this by using scope.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Let me show you how:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
function createPerson() {    
"firstName" = "John";    
"lastName" = "Doe";      
var returnObj = {    
"getFirstName" : function(){      
return firstName;  
},    
"getLastName" : function(){      
return lastName;  
},  
"setFirstName" : function(name){      
firstName = name;  
},    
"setLastName" : function(name){      
lastName = name;  
};  
return returnObj
};
var =createPerson();
console.log(person.getFirstName());
person.setFirstName("Jane"));
console.log(person.getFirstName());// this outputs 'Jane' on the console

Here, we prevented the access of variables firstName and lastName anywhere else by enclosing them in a scope. First, we created a function called createPerson, then we created our variables firstName and lastName(both closures) inside our createPerson scope. These two properties are only accessible by these two functions, getFirstName and getLastName that were created. All thanks to closures. However, the object itself, returnObj, does not remember the two variables and so does not have access to them. Following that, we created setFirstName and setLastName to a function and then returned both first and last names because both setters were created with the scope.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Please note that all four functions works on the closure variables firstName and lastName. On line 23, when you run that console.log, you get ‘Jane’ printed out on your console.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Here, we removed the property-firstName and lastName from the object because there’s no way we can make a property private in JavaScript other than using the module pattern. Using the module pattern, we moved both closure variables-firstName and lastName, so that the functions remember them and using the function is the only way to access those variables.

Why do we need closures?

Closures are very important as they can control what is and isn’t in the scope of a particular function. They also control which variables are shared between siblings functions in the same lexical scope. Additionally, they also help simplify our code and make our lives as programmers easier.  

0 reactions
heart.png
light.png
money.png
thumbs-down.png

One of the most important reasons why we need closures is that they help with ‘Data Hiding and Encapsulation’. With Closure, we can store data in a separate scope and share it only when we deem fit. Closure also helps prevent leaking or exposing data where it is not needed. When we use closures for data encapsulation, the enclosed variables are only within the scope of the containing (outer) function. What this means is that we can’t access the data from an outside environment except through the methods defined in the object.  

0 reactions
heart.png
light.png
money.png
thumbs-down.png

To demonstrate, consider the following example code:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
(function () {    
var p;    p = 0;    
function bar() {        
p += 1;    
}    
Count.prototype = {        
CountInc: function () {            
return p;        
}    
};    
window.Count = Count;}());

From the example above, the p variable is accessed by the Count constructor and the CountInc method. p's value is still retained even after the Immediately Invoked Function Expression (IIFE) method is executed and exits the constructor and the method. IIFE are functions that run as soon as they are defined. This is a very popular use case that we will get to see in practice and real world use cases without even knowing it’s closure in place.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Additionally, closures are also useful for associating data with a function that operates on that data. This is similar to object-oriented programming, where an object allows us to effectively associate the same object's properties with one or more methods.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

The code is attached as a single function that is executed in response to the event.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Understanding the scope chain

In JavaScript, every closure has three scopes, namely:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
  1. Global
  2. Function scope/local scope
  3. Block

Now let's explore each of them below.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Global Scope:

0 reactions
heart.png
light.png
money.png
thumbs-down.png

When a variable defined is not inside a function or a pair of curly braces, { } then we can say that such a variable exists in the global scope and therefore can be accessed from anywhere in the program.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

For example:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
var greeting = 'Welcome Home';
//greeting is a global variable that can be accessed from anywhere

function greet() {  
console.log(Welcome Home);
}
// Prints 'Welcome Home
greet(); //We get "Welcome Home" printed on the console because the greet function could access the variable.

Function/local scope:

0 reactions
heart.png
light.png
money.png
thumbs-down.png

When variables are declared inside a function, they can only be accessed from within that function. That means they can’t be accessed from outside the function scope.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

For example,

0 reactions
heart.png
light.png
money.png
thumbs-down.png
function greet() {  
var greeting = 'Welcome Home';  
console.log(greeting);
}
// Prints 'Welcome Home'
greet(); //try calling the function outside of its scope==>Uncaught ReferenceError: greeting is not definedconsole.log(greeting);

Block Scope:

0 reactions
heart.png
light.png
money.png
thumbs-down.png

With ECMAScript 2015 (or ES6), let and const keywords, variables can only be scoped to the nearest pair of curly braces. Unlike var variables, they can’t be accessed from outside that pair of curly braces.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

For example,

0 reactions
heart.png
light.png
money.png
thumbs-down.png
{  let greeting = 'Welcome Home';  
var course = 'JavaScript';  
console.log(greeting); // Prints 'Welcome Home'
}
// Prints 'JavaScript'
console.log(course);

// Uncaught ReferenceError: greeting is not defined
console.log(greeting);

Emulating private methods with closures

One way to use a closure is to emulate private methods. Private methods can only be called by other methods in the same class. These methods/functions in JavaScript are accessible within their scope. These variables also allow the functions defined within their scope to have total control over how they are manipulated. JavaScript does not give us the luxury of specifying whether variables and methods associated with objects should be public or private in their declaration, but it does give us a way to implement them, as seen below:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
var counter = (function() {  
var privateCounter = 0;  
function changeBy(val) {    
privateCounter += val;  
}
return {    
increment: function() {      
changeBy(1);    
},
decrement: function() {      
changeBy(-1);    
},
value: function() {      
return privateCounter;    
}  
};
})();
console.log(counter.value());  // 0.

counter.increment();
counter.increment();
console.log(counter.value());  // 2.

counter.decrement();
console.log(counter.value());  // 1.

Source: MDN

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Here, though, there is a single lexical environment- counter that is shared by the three functions: counter.increment, counter.decrement, and counter.value. The lexical environment contains two private items: a variable called privateCounter, and a function called changeBy. These private members cannot be accessed from outside the anonymous function, counter. Instead, you can access them using the three public functions that are returned from the anonymous wrapper. The three public functions are closures that share the same lexical environment and can each access the privateCounter variable and the change By function through scoping.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

In summary,

0 reactions
heart.png
light.png
money.png
thumbs-down.png
  • Whenever you have a function inside another function, then, you have a closure.
  • Closures, whether inner functions or functions returned by another function, have a reference to their lexical environment during the time of their creation.
  • You can use closures to create private data, whether it’s a private method or a private variable.
  • Every closure has three scopes: global, local and block scope

Conclusion

In this tutorial, we have looked at closures and how we can use them in our code with real world examples. We also covered why you should use closures alongside the scope chain, and of course, how to emulate private methods with closures.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

JavaScript closures are one of those concepts that may seem difficult to understand at first glance, but once you understand them, you will gain a better insight into how they work, and most importantly, the kinds of problems you can use them to solve.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Pull Quotes

Closure is one of those things in JavaScript that permeates the entire language. It is all around you in JavaScript. You just have to use it and embrace it.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Closure is when a function can remember and access its lexical scope even when it’s invoked outside its lexical scope.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Further resources

These are some useful links you can check out if you want to dive deeper into some of the things we discussed above.
You don’t know JS: Scope and Closures by Oreilly 
Mozilla Developer Network 

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Author Bio

Queen is a front-end developer and a tech enthusiast. She’s passionate about learning and sharing what she learns with others. 

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Author Links

Twitter

0 reactions
heart.png
light.png
money.png
thumbs-down.png

LinkedIn

0 reactions
heart.png
light.png
money.png
thumbs-down.png

This article was also published here.

0 reactions
heart.png
light.png
money.png
thumbs-down.png
6
heart.pngheart.pngheart.pngheart.png
light.pnglight.pnglight.pnglight.png
boat.pngboat.pngboat.pngboat.png
money.pngmoney.pngmoney.pngmoney.png
by Queen Nnakwue @qnnakwue. Queen Nnakwue is a software engineer et technical writer based in Lagos, Nigeria. Read my stories
Join Hacker Noon

Create your free account to unlock your custom reading experience.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK