Assessing the output of a saved function within a loop using a variable declared with let

From what I understand, when the loop variable of a for loop is declared using var, any changes made to that variable are reflected globally. For example:

var printNumTwo;
for (var i = 0; i < 3; i++) {
  if (i === 2) {
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(printNumTwo());

In the code snippet above, the console will display 3. This is because in the final iteration, the variable i will be equal to 3. Therefore, when calling printNumTwo, the updated value of i will be returned. However, this behavior changes when using let:

let printNumTwo;
for (let i = 0; i < 3; i++) {
  if (i === 2) {
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(printNumTwo());

The second code snippet will output 2.

let printNumTwo;
for (let i = 0; i < 3; i++) {
  if (i === 2) {
    printNumTwo = function() {
      return i;
    };
    i = 3;
  }
}
console.log(printNumTwo());

Surprisingly, the third code snippet prints 3. What could be the reason behind this difference?

source: The initial two code blocks can be found here.

Answer №1

The initial scenario demonstrates how var confines i within the function, causing i++ to transform i from 2 to 3, ultimately halting the loop. At this point, the sole value of i is 3, and when printNumTwo is called, it returns i which is 3.

In contrast, the following example shows that using let limits the scope of i to the block level, resulting in printNumTwo encapsulating it. During the final iteration of the loop, i stands at 2, and consequently, printNumTwo outputs i as 2. (Although a new i emerges with the value of 3, it remains unused by any function).

Moving on to the third instance, once again utilizing let isolates i within the block. This time, however, the difference lies in the assignment i = 3;, effectively setting all existing i instances to 3. Consequently, the last generated function (while also replacing previous ones) yields i as 3.

Answer №2

Why does the above code output 3 instead of the expected value?

The reason for this is that you are assigning the value of 3 to the variable i which is being closed over by the function printNumTwo. The timing of the assignment relative to when printNumTwo was created is not important; what matters is that it is the variable i that is being used within printNumTwo.

The distinction between using var and let in for loops lies in the fact that a new variable is created for each iteration of the loop body with let. Since you are updating this variable within the loop body, the function closing over it (printNumTwo) will observe this updated value when invoked later.

To put it simply:

function create(i) {
    // This function captures `i`
    const fn = function() {
        return i;
    };

    // This updates the captured `i` value
    ++i;

    return fn;
}
const printValue1 = create(1);
console.log(printValue1()); // Outputs 2 (1 + 1)

const printValue27 = create(27);
console.log(printValue27()); // Outputs 28 (27 + 1)


In reply to a comment on the initial question:

A similar scenario occurs in the second code block (i++ in the update section of the for loop), but why does it output 2?

Ah! I now understand the confusion. While there is an update to i, it affects a different instance of i compared to the one enclosed by printNumTwo.

The update in the for loop's update section happens on a fresh variable representing the next iteration at the beginning of that iteration, rather than on the variable from the previous iteration at the end of that iteration. Here's how it unfolds:

  • Create a new version of the iteration variable (let's call it iNew)
  • Copy the value of the existing iteration variable (let's call it iOld) into the new variable (iNew = iOld)
  • Execute the update logic using iNew (iNew++)

This explains why the original i remains at 2, while the new one assumes the value of 3.

Answer №3

The scoping of var is limited to the function, whereas the scope of let is restricted to the block.

When a value is assigned to the printNumTwo function, the value of i remains 2 regardless of any changes made to i afterwards.

This example illustrates the distinction between the behaviors of var and let.

for(var i=0; i<3; i++){
    setTimeout(() => console.log('var', i))
}

for(let i=0; i < 3; i++){
    setTimeout(() => console.log('let',i))
}

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

Transform my Angular implementation to TypeScript programming

After spending a year coding Angular and seeing great progress, the buzz around TypeScript has caught my attention. While there are plenty of tutorials and blogs on the topic, there seems to be inconsistency in the recommendations. How should the app.js fi ...

Understanding when the @Input parameter has been modified

I need a way to trigger a function every time the @Input value is accessed, regardless of whether it has changed or not. Here's what I have tried so far: ngOnChanges(changes: { [propName: string]: SimpleChange }) { if( changes['inputName' ...

Hide the element, update its content, and smoothly transition back

I am looking to add dynamic content to an element on my HTML page, with the inserted HTML transitioning smoothly from 0% to 100% opacity. HTML <div id="content"></div> CSS #content { opacity: 1; transition: opacity .5s ease-out; -moz ...

Initiate jison states using JSON structure

After an extensive search through documentation and forums, I am still struggling to find the correct syntax for Jison start condition using JSON format in node.js. > ** The documentation at http://zaach.github.io/jison/docs/ states: > // Using the ...

Is sendFile causing an error due to an invalid JSON format?

Whenever I try to send a file to a client for download, I encounter an exception saying that the JSON is invalid. Is there a better way to send the file, perhaps using res.download and setting the content as JSON? I want to avoid using AngularJS FileSaver ...

Cleanse the array in jQuery by removing any unusual characters

I have a specific task involving an array that needs to be sent to a web service. The URL in question is as follows: http://localhost:4025/vmp_webservice.asmx/LoadService2Daily?fromDate=2014-05-26+00%3A00%3A00&toDate=2014-05-26+23%3A59%3A01&campa ...

Adjusting the Size of a Static Banner

I have a quick question. I've been trying to create a fixed banner that will scale when the page is resized, but I'm having some trouble with the phrasing in Google search. My issue is that when using a percentage width for the large container, t ...

Extract dynamic JSON objects found within a JSON response

I have encountered a challenge with a dynamic JSON object that I am working with { "servers":[ { "comp1":{ "server1":{ "status":"boxup", "ar":{ "0":"95.61" }, ...

How to efficiently use nested $.each() in DataTables with jQuery

After receiving Json data from the server, I utilize DataTables to display the information accordingly. The json contains multidimensional arrays with rows consisting of columns that may have more than one value. Here's an excerpt: { "info_table ...

Converting ampersands to HTML special characters in AJAX JSON transformations

My PHP script returns a JSON-encoded response like this: //PHP $response = array('type' => 'success', 'content' => '&&!%$#!some words'); echo json_encode($response); return; The JavaScript code then a ...

Is it possible to assign a class to the initial word within a designated class?

How can I customize the first and second word of a specific class in my code? This is an example of my current code: <h2 class="content-heading">Latest News</h2> I would like to achieve something similar to this: <h2 class="content-headi ...

What is the best way to maintain a search input history while navigating search results and returning using the browser button, similar to Google Search in Angular2?

When I enter a keyword into a search input, press enter, and see the search results, I can then click on a result to navigate to its info. But how can I retrieve the originally searched keyword if I use the back button in my browser? ...

What is the best way to position my content next to my sticky sidebar for optimal visibility?

Just starting out with coding and tackling my initial project using reactJs and bootstrap 5. My aim is to create a sticky side navbar that remains fixed on the side while my content displays next to it, even when navigating through different routes. Unfort ...

Modifying specific attributes of an object within the $scope: A step-by-step guide

When working with Angular, if you have code in the view that looks like this: <span ng-model="foo.bar1"></span> <span ng-model="foo.bar2"></span> <span ng-model="foo.bar3"></span> Due to how Angular maps objects, you c ...

Tips for creating a jquery modal form that can be reused

I currently have the following files : *vehicule_parc.php :* <script language=javascript src="../js/vehicule_parc.js"></script> <h3 class="headInfoBox" id="cch">Fuel Consumption >></h3> <hr /> <div id="cc"> ...

What is the reason behind every single request being treated as an ajax request?

Recently, I embarked on a new application development journey using rails 4.0. However, I've encountered an unexpected situation where every request is being processed as an ajax request. For instance, consider this link: =link_to "View detail", pr ...

Exploring Three.js on Cordova with WebGL

I am working on developing a mobile app using Three.js on Cordova. While the app runs smoothly on a PC browser, it encounters an issue when trying to create the WebGL context on a Samsung Note 3 device. The specific error message is: THREE.WebGLRenderer ...

Webpack encounters issues when compiling ES6 syntax from external packages

I am encountering an issue with integrating an ES6 npm package, specifically one called gamesystem, into my project and building it with webpack (along with babel). For some reason, the build fails to process any ES6 code within the external dependency. Ho ...

Steps for making a linked list through the drag-and-drop method

I'm attempting to make a dynamic list where users can drag and drop links from other websites, like a wishlist of sorts... <style> .droptarget { float: left; width: 100px; height: 35px; margin: 15px; padding: 10px; ...

A series of divs continuously scrolling in succession with a stationary title/header

My web page contains multiple div sections, each with its own content. I need the page to load initially with all sections visible. Then, I want the page to auto-scroll so that the header of the first section remains fixed while its contents scroll. Once t ...