The conundrum of JavaScript closures

→ Click here for the code on jsFiddle

function f1(){
    var n=999;

    nAdd=function(){n+=1;};

    function f2(){
        alert(n);
    }
    return f2;
}

var result = f1();
var result2 = f1();

result();  // Output: 999
nAdd();
result2(); // Output: 1000
result2(); // Output: 1000
result();  // Output: 999

I am currently studying JavaScript closures, and the code snippet above has left me feeling perplexed. The initial call to result() displays 999, which is understandable.

After invoking nAdd(), the subsequent call to result2() yields 1000. This behavior can be attributed to both result2() and result() pointing to the same instance of f1().

However, I am puzzled as to why the final call to result() outputs 999 instead of 1000.

Answer №1

Whenever f1() is invoked, a new closure is generated with its own unique local n variable.

Nevertheless, the global nAdd variable gets overwritten each time f1() is called, resulting in nAdd() only incrementing the n variable within the most recent closure.

UPDATE: To independently increase the values of n in each closure, you can implement something like this:

function f1(){
    var n=999;
    return {
        incrementN : function(){n+=1;},
        getN : function f2(){console.log(n);}
    }
}    
var result = f1();
var result2 = f1();
result.getN(); // 999
result.incrementN();
result2.getN();//999
result2.incrementN();
result2.getN();//1000
result.getN();//1000

In this scenario, f1() returns an object with two methods that are not globally declared and both interact with the local n variable specific to their respective closure.

Answer №2

While the existing answers are solid, I believe incorporating a visual aid would enhance comprehension.

Answer №3

Every time you invoke the function f1(), several actions are taken:

  • A new local variable named n is created with a value of 999
  • An unnamed function is generated and assigned to the global variable nAdd, which updates the value of n (replacing any existing function stored in nAdd)
  • A new function is constructed and returned, which displays an alert containing the current value of n

Since you call f1() twice, these steps are repeated twice. The second invocation replaces the previous function assigned to nAdd with one that alters the value of the second n.

After this process, your setup includes:

  • result() triggering an alert displaying the value of the first n
  • result2() prompting an alert showing the value of the second n
  • nAdd() incrementing the value of the second n

When result() is executed at the end, it alerts 999 since it retrieves the unaltered value of the first n.

Answer №4

result and result2 store the outcomes of separate calls to f1, resulting in distinct instances of the local variable n. The values of local variables within a function can vary with each call, even without closures being part of the equation.

Answer №5

The line of code nAdd=function(){n+=1;}; establishes a global function that acts as a closure within the f1() function. A closure in JavaScript has access to all variables in the scope where it was created. Therefore, each time you invoke f1(), a new instance of nAdd() is generated with the value of n being linked to the value of the variable var n specific to that particular call of f1().

In the provided code snippet:

var result = f1();
var result2 = f1();
result(); // Produces output: 999
nAdd();         // This was created by invoking "var result2 = f1();" and shares the same 'n' value as the function in result2
result2();//Produces output: 1000
result2();//Produces output: 1000
result();//Produces output: 999

Answer №6

Two distinct closures are formed by the result and result2, each with its own value of n. By defining n as a global variable outside of the f1() function, you ensure that both results access the same global n:

var n = 999; function f1(){
nAdd = function(){n+=1;};
function f2(){
console.log(n);
}
return f2;
}
var result = f1();
var result2 = f1();
result(); // 999
nAdd();
result2();//1000
result2();//1000
result();//1000

Answer №7

Here is how it works:

var nAdd;
function f1(){
    var num=999;

    nAdd=function(){num+=1;};

    function f2(){
        alert(num);
    }
    return f2;
}

var result = f1();//var nAdd=function(){num+=1;} num=result.num=999

var result2 = f1();//var nAdd=function(){num+=1;} num=result2.num=999

var result3 = f1();//var nAdd=function(){num+=1;} num=result3.num=999

nAdd();

result();  // 999

result2(); // 999

result3(); // 1000

var r1 = f1();//var nAdd=function(){num+=1;} num=r1.num=999

var r2 = f1();//var nAdd=function(){num+=1;} num=r2.num=999

nAdd();

var r3 = f1();//var nAdd=function(){num+=1;} num=r3.num=999

r1();  // 999

r2(); // 1000

r3(); // 999

var res1 = f1();//var nAdd=function(){num+=1;} num=res1.num=999

var res2 = f1();//var nAdd=function(){num+=1;} num=res2.num=999

nAdd();

var res3 = f1();//var nAdd=function(){num+=1;} num=res3.num=999
nAdd(); 
nAdd();
nAdd();   

res1();  // 999

res2(); // 1000

res3(); // 1002

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What steps can I take to stop a browser from triggering a ContextMenu event when a user performs a prolonged touch

While touch events are supported by browsers and may trigger mouse events, in certain industrial settings, it is preferred to handle all touch events as click events. Is there a way to globally disable context menu events generated by the browser? Alternat ...

Error: Jest react testing encountered an issue when attempting to read the property 'type' from an undefined value

While conducting tests on my app components created with the material UI library using jest and enzyme, I encountered an error in one of my packages. Here is a screenshot of the error: Click here to view ...

Tips for extracting the most deeply nested object in a JSON file using JavaScript

Is it possible to access the innermost object without knowing the path names? Consider this JSON example: const data = { first: { second: { third: {innerObject} } } ...

Encountered an issue with md-autocomplete: Attempting to read property 'success' of an undefined element

I encountered an issue while using Material Angular framework and md-autocomplete. The error message I receive is: Cannot read property 'success' of undefined. Below is the snippet of my code: /*My app.js*/ var app = angular.module('app&apo ...

My goal is to utilize intercooler.js to load content dynamically into a bootstrap 4 modal

I'm attempting to populate a modal with content using intercooler. You can view an example here: http://jsfiddle.net/qvpy3coL/3/ I'm struggling to make it work and I'm curious if this is feasible, or if there might be a conflict with the b ...

Tips for referencing Google Maps initialization in individual files within a website application

After setting up my Google Maps API snippet: <script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"></script> in the index.html file, I encountered the error: Uncaught InvalidValueEr ...

It is impossible for JavaScript to set the position attribute directly in the element's style property

I'm new to javascript and I need some help. I created a function that adds a div with the id "test_div" to the body. However, when I try to set the position using "element.style.position", it doesn't work. I figured out that I can apply styles us ...

Expanding on current features with jQuery to enhance the code by incorporating validation checks for input boxes with values

Seeking assistance as a newcomer to the jQuery library. I have existing code that checks for selected values in select boxes and enables the search button accordingly. Now, I need help modifying the code to also check for input values in input boxes simul ...

Serializing Form Data with Checkbox Array

I am currently utilizing JQuery to submit a form using the form.serialize method. However, within the same form, there is an array of checkboxes that are dynamically created by a PHP function. Here is the structure of the form: <form class="form" id="f ...

The main attribute in the NPM package.json is missing or has no appropriate entry

I'm really struggling to figure out the best approach for setting up my package.json file. I have a JavaScript module that contains multiple reusable JS files, let's call it Module1. In Module1's package.json, the name attribute is set to " ...

The issue of why iterating over an array of objects does not function properly in React JS

P.S: I have made some modifications to the code below. Extracting the doctor's value from JSON data, updating the state, and then mapping it to print out the values. Initially, there is only one doctor, but in the future, there could be more than one ...

JavaScript error type mismatch

Currently, I am utilizing select2.js to highlight a specific li element that is received as a response. var cityCounter = -1; var sul = $('.select2-search-choice'); $(".select2-input").keyup(function (e) { // TODO CODE // console.log($( ...

Can the color of an icon be altered by selecting a list item in VueJS?

I am currently working on a VueJS Dropdown Menu implementation that involves displaying an icon. When this icon is clicked, a Dropdown Menu containing 3 other icons should appear. Furthermore, upon clicking one of these icons, I intend for the original Dro ...

Leverage the power of sharing scope across controllers in AngularJS for

I am facing an issue with sharing scope between two AngularJS controllers. In the first controller, I retrieve data from the server and store it in a scope variable called myData. This variable has multiple items but I only care about one particular item - ...

Show the ajax appended html only after reaching a specific threshold

I am currently utilizing AJAX to fetch additional results from my database. Below is the basic script I am using: $('#loadmorebuilds-div').click(function() { $.ajax({ url: 'includes/loadmorebuilds.php?type=' + type + &ap ...

Exploring promise chaining in mongoDB (and mongoose): A guide to effectively utilizing .save() following .then() and gracefully exiting a promise chain upon sending a response

Currently, I have implemented a code snippet for user signup that involves several steps. Initially, I validate the user input to ensure its correctness. Following this, I verify if the user already exists in the system, and if so, I return a response of 4 ...

transforming the elements within a div into a visual representation

I'm in the process of developing a web-based image editor. My main div will have multiple nested div elements within it. My goal is to save the entire main div as an image in a designated folder when the user clicks on a save button. I initially atte ...

Received an error while using an Express router: "Unable to access property 'caseSensitive' of undefined."

javaScriptCode app.js const express = require('express') const app = express() const {route} = require('./routes/route') app.use(express.static('./public')); app.use(express.json()); app.use(express.urlencoded()); app.use(rout ...

The timestamp indicating when the local file was last modified, using JavaScript

My current JavaScript project involves reading XML files stored in the %appdata% directory using jQuery's $.ajax function. Because the file is located in %appdata%, my JavaScript code has the necessary permissions to read and write to the file. For e ...

Convert require imports to Node.js using the import statement

Currently learning NodeJs and encountering a problem while searching for solutions. It seems like what I am looking for is either too basic or not much of an issue. I am working on integrating nodejs with angular2, which involves lines of code like: impo ...