Patrick Carey is a Cengage author, presenter, and has co-authored or coauthored more than 20 academic and trade texts in the software industry.
Closures are one the most important concepts in JavaScript programming, but they are also one of the most misunderstood. Closures are often discussed in job interviews. They might also be asked to provide code examples that involve closures. Mozilla.org has a formal definition of closure.
A closure is a combination of a function that has been bundled together (enclosed), and references to its surrounding environment (the lexical context).
I believe it is best to explain the concept of scope to help students understand closures and how they can be applied to programming projects.
Variables and Scope
A variable’s existence is limited by its scope when it is defined. Scope defines where the variable can be used or referenced. A variable declared using the let keyword has a limited scope. It is only valid for the command block in the which it was first declared. The topic variable is only found within the command block for the writeLog() function in the following example. It is not possible to exist outside of this context.
{function writeLog() function writeLog() topic = “closures!” “; console.log(`Let’s learn about $topic`);}writeLog(); // logs “Let’s learn about closures! “console.log (Learn about $topic // Uncaught referenceError: topic was not defined. The scope of a variable is extended down through the chain of nested blocks and functions in these cases. This principle is illustrated by the following code. The topic variable’s scope extends into the function nested().
{function writeLog() function writeLog(): let topic = “closures!” “; nested(); function nested() console.log(`Let’s learn about $topic`); writeLog(); // logs “Let’s learn about closures!|”; nested(), function nested() console.log(Let’s learn more about $topic writeLog() // logs “Let’s learn more about closures!} The nested() function “knows what the topic variable means because of a principle in programming called lexical Scope. This principle allows variables, functions and other objects to be defined according to their physical location within the source codes. The JavaScript Interpreter recognizes topic variables because they are part of the larger context that includes the declaration of topic variable and creation of nested() function.
The interpreter applies lexical context when evaluating all variables it encounters. It begins by searching for a matching declaration of a variable within the current command block or function. If it doesn’t find one, the interpreter continues to search for the declaration at higher levels until it finally finds it. If there is no declaration at any level, the interpreter reports an error because it cannot find the variable name. The entire structure of variable statements is called the lexical environment. It includes the function and all variables that exist within it.
JavaScript Closures, and the Lexical Environment
Understanding closures is possible by understanding the concept of the lexical context. The following code demonstrates why. It runs the nested() function in a context that is not defined by the writeLog() function.
{function writeLog() function writeLog(): let topic = “closures!” “; function nested() console.log(`Let’s learn about $topic`); return nested;}let myClosure = writeLog();myClosure();// logs “Let’s learn about closures! “MyClosure() can only be called in the last line because it returns the writeLog() function. The code still works despite the fact that the topic variable is not referenced in its lexical environment. Closures that copy the lexical environment where the topic variable was found are the reason. Closures “enclose” all information about the function, including its context within larger source code. This is why the topic variable retained its meaning even though it was referenced outside of the writeLog() function.
JavaScript Closures & Program Loops
Closures are often encountered in program loops that call functions at every iteration. Consider the following program loop, which calls an anonymous function that displays the value of a countervariable after a one-second delay.
for (let i = 0; i < 3; i++) setTimeout(function() console.log(`The counter is $i`); , 1000);// logs "The counter is 0"// logs "The counter is 1"// logs "The counter is 2"The setTimeout() method delays logging anything until after the loop is finished and counter variable, i, removed from memory. Despite this, the counter variable value at the time that the setTimeout() was called is preserved.
This behavior occurs because the program loop copies the function nestled within the setTimeout() method and encloses it. It also copies its lexical environment. The anonymous function is a fact.