Using the "let" keyword in JavaScript can create closures

function first(){
    var items = document.getElementsByTagName("li");

    for(var x = 0; x < items.length; x++){
        items[x].onclick = function() {
            console.log(x);
        }
    }
}

function second(){
    var items = document.getElementsByTagName("li");

    for(var x = 0; x < items.length; x++){
        (function(val) {
            items[val].onclick = function() {
                console.log(val);
            }
        })(x);
    }
}

function third(){
    var items = document.getElementsByTagName("li");

    for(let x = 0; x < items.length; x++){
        items[x].onclick = function() {
            console.log(x);
        }
    }
}

The list contains four elements. The results of the three functions:

first: 4 4 4 4
second: 0 1 2 3
third: 0 1 2 3

I'm puzzled by the output from the third function. In the second function, a new function object is created with each IIFE call, resulting in a new 'val' variable. However, in the third function, there is only one instance of the variable x, so why do we get: 0 1 2 3

If I've misunderstood something, kindly correct me.

Answer №1

According to the documentation on let from MDN, there is an example that demonstrates this specific scenario in the Cleaner Code in inner functions section:

for (let i = 1; i <= 5; i++) {
  let item = document.createElement('li');
  item.appendChild(document.createTextNode('Item ' + i));

  item.onclick = function(ev) {
    console.log('Item ' + i + ' is clicked.');
  };
  list.appendChild(item);
}

This example works correctly because each instance of the anonymous inner function refers to a unique instance of the variable i. If you were to replace let with var, all inner functions would return the same final value of i: 6. Additionally, by creating new elements within the loop's scope, we keep the code cleaner.

The concept also applies to your situation where using let ensures that each iteration of the loop has its own distinct instance of x. This is due to let having block-level scope compared to the global function scope of var.

Answer №2

According to the documentation provided at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

The use of let enables the declaration of variables with limited scope to the specific block, statement, or expression in which it is utilized. This stands in contrast to the var keyword, which declares a variable either globally or locally within an entire function without regard to block scope.

Variables declared using var get hoisted like all other variables.

On the other hand, when using let, the scope is confined to the block where it is defined.

Answer №3

This example showcases the intricacies of using the let keyword.

Utilizing Let within a block (such as a for-loop) means that it binds the variable to each iteration of the loop. Consequently, once the loop completes, there will be 4 items (ranging from item[0] to item[3]) responsive to click events.

The for-loop in the third function generates the following actions:

items[0].onclick = function() {
        console.log(0);
   }
items[1].onclick = function() {
        console.log(1);
   }
items[2].onclick = function() {
        console.log(2);
   }
items[3].onclick = function() {
        console.log(3);
   }

To delve deeper into the usage of Let, explore more on MDN's article on Let. It provides insights into other fascinating use cases as well.

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

Meteor: The call stack has surpassed its maximum size limit

I attempted to perform an action that I have done several times before without encountering any errors. My goal is to retrieve all documents where the X field matches the value Y in my Meteor app: JS: (template helper) 'friendPictures' : funct ...

Display information from an array in checkboxes. If the same data appears in another array, the corresponding checkbox in React will be automatically checked

I currently have two arrays. The first array, let's call it arr1, contains multiple objects such as [{"Name":"Mr.X"},{"Name":"Mr.Y"},{"Name":"Mr.Z"}]. The second array, named arr2, holds a few values like [{"Name":"Mr.Z"}]. My goal is to display all ...

How to eliminate duplicate items in an array and organize them in JavaScript

I am looking to eliminate any duplicate items within an array and organize them based on their frequency of occurrence, from most to least. ["57358e5dbd2f8b960aecfa8c", "573163a52abda310151e5791", "573163a52abda310151e5791", "573163a52abda310151e5791", "5 ...

Troubleshooting the NestJS @InjectModel() dependency issue: Solutions and Fixes

userLink.api.ts import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Document, Types } from 'mongoose'; import { User } from 'src/users/schemas/users.schema'; export type UserLinkDocument = UserLink & ...

How can you tell when directionsService has finished processing and returned its status?

Within the code snippet below (keep an eye on the error console!), I am rapidly querying Google Maps for ten different locations to determine whether it can calculate a route to them or not. While this method does work, I require the result from Google to ...

Exploring the process of iterating through arrays within an object in vue.js using the v-for directive

Is there a way to iterate through an output object using the v-for template in Vue.js? new Vue({ el: app, data: { output: { player: [1, 5, 61, 98, 15, 315, 154, 65], monster: [14, 165, 113, 19, 22], }, }, }); <script src= ...

What is the best way to create an Office Script autofill feature that automatically fills to the last row in Excel?

Having trouble setting up an Excel script to autofill a column only down to the final row of data, without extending further. Each table I use this script on has a different number of rows, so hardcoding the row range is not helpful. Is there a way to make ...

Node Js seems to be taking quite a while to output to the console

Hello, this is my first time posting on Stack Overflow so please bear with me if I make any mistakes. I created a button that, when clicked, decrements the quantity by one. After updating the UI, I send the data to the server. However, when I console log t ...

What could be causing media queries to not update values even after being changed through JavaScript?

I have a simple navigation bar on my website, featuring links to different subpages. To enhance the user experience on mobile devices, I added a hamburger menu icon that is displayed on smaller screens. The links in the navigation bar are hidden using CSS ...

The concept of undefined in JavaScript when an if condition is applied

In Node.js, there is a method used to handle API requests. An unusual behavior occurs when dealing with req.query.foo - even if it has a value defined, it becomes undefined when used in an if condition as shown below. Additionally, another req.query.foo ...

Having difficulty executing the multichain-node npm module on the client side (browser)

let blockchain = require("blockchain-node")({ port: 6001, host:'localhost', user:'myuser', pass:'mypassword' }); blockchain.getInfo((error,info) => { if(error){ throw error; } consol ...

Getting the length of child elements in Angular using ngFor loop

Can anyone help me figure out how to check the length of a child element in my Angular *ngFor loop? I am fetching data from a real-time firebase database. What am I doing wrong? Here is the code snippet I am using: <div *ngFor="let event of events"> ...

Adjusting the spacing between a pair of radio buttons within the identical group

Is there a way to adjust the spacing between two horizontal radio buttons? The buttons are part of the same group, and I want to shift the right button ("Clear Selection") further to the right so it aligns with the buttons in another group below. ...

How can I utilize the "remark" tool to handle Markdown files with URLs that don't adhere to Markdown formatting? Are there any supplemental plugins available for this

My markdown file has frontmatter and sometimes includes inline URLs that are not properly formatted with markdown syntax. I'm looking for a way to handle these non-markdown URLs within the markdown file - possibly by parsing them into HTML URLs using ...

Getting EdgesHelper to align properly with Mesh in Three.js

Within a dynamic scene, multiple mesh objects (specifically cubes) have been included. A unique EdgeHelper has been generated for each cube to track its movements and rotations. Whenever a particular cube mesh is selected, I am aiming to alter the color o ...

Having trouble with Vue component not showing updated data after axios POST request issue

Hi there, I'm facing an issue and could really use some guidance from a skilled Javascript Wizard. Here's the problem: I have a Laravel collection that I'm passing to a Vue component. Within the component, I am looping through the collecti ...

Notification box appears only when closing the window, not when reloading the page

I've been trying to find a way to remind my users to log out before closing the window. I found this code that seems to work: window.onbeforeunload = confirmExit; function confirmExit() { return "It's best to log out before you close this pa ...

An error occurred in Node.js while parsing data: Headers cannot be set after they have already been sent to the client

I am currently using a CSV parser to read data from a CSV file. I then pass this data in object format to an EJS template file for printing. However, when I try to stringify the data, I encounter an error. The error message is as follows: Error [ERR_HTTP_ ...

Press anywhere else on the screen to dismiss the bootstrap menu

I've been attempting to find a solution for closing the Bootstrap menu when clicking outside of it in a mobile window size, but I just can't seem to make it work. I did manage to get it working when clicking one of the 'a' links using t ...

Implementing dual pagination components in Vue JS for dynamic updates on click

Having two pagination components on a single page is convenient for users to navigate without scrolling too much. One component is placed at the top and the other at the bottom. The issue arises when I switch to page 2 using the top component, as the bott ...