Kshri
Kshri

Reputation: 414

Closure inside a loop in Javascript

I have a simple function which has another function inside its for loop. The main function returns the sub function. When the main function is called, the loop runs but the sub function is not yet executed since it is not yet called. The sub function is called after the loop has been executed and hence the value of i points to the value of the last element of the array. If I want this to have a new binding to each of the values in the array, how do I fix it?

function getName() {
    const arr = ['a', 'b', 'c', 'd'];
    for (let i = 0; i < arr.length; i++) {
        function sendName() {
            alert(arr[i]);
        }
    }
    return sendName;
}
var receiveName = getName();
receiveName();

Upvotes: 0

Views: 117

Answers (5)

Oleksandr Pyrohov
Oleksandr Pyrohov

Reputation: 16226

You might want to use an anonymous wrapper instead:

function getName() {
    const arr = ['a', 'b', 'c', 'd'];
    for (let i = 0; i < arr.length; i++) {
        (function() {
            alert(arr[i]);
        })(i);
    }
}
getName();

Also, as other people mentioned in comments, such implementation makes little sense until you provide more detailed explanation about why do you need it. There probably should be more elegant solutions that will fit your requirements.

Upvotes: 1

Shruti Singh
Shruti Singh

Reputation: 181

This is because its getting called only once ie... even though

function sendName(){
 alert(arr[i]);
    }

sendName is changing its assigned value four times but it is called only once, therefore it is only alerting "d", since d is the last value assigned. If you want to alert "a", "b", "c", "d", call the function inside the loop.

Upvotes: 0

nirazlatu
nirazlatu

Reputation: 993

I think there is no point to wrap alert(a[i]) in function scope as we already are using let and it provides a block scope.

We could just use the following function and it can output the required result.

function getName() {
    const arr = ['a', 'b', 'c', 'd'];
    for (let i = 0; i < arr.length; i++) {
            alert(arr[i]);
    }
}
getName();

Upvotes: 1

Shalitha Suranga
Shalitha Suranga

Reputation: 1146

You can use array to store different functions. This example will return different letters according to N.

function getName() {
const arr=['a','b','c','d'];
  let a = [];
	for(let i = 0;i<arr.length;i++) {
		a.push(function () {
			alert(arr[i]);
		});
	}
	return a;
}
var receiveName=getName();
let N = 0; // returns a
receiveName[N]();
console.log(receiveName);

Hope it helps

Upvotes: 1

Oskar
Oskar

Reputation: 2607

You can use the bind function to achieve what you want:

function sendName( name ) {
  alert( name );
}

function getNames() {
  const arr = [ 'a','b','c','d' ];
  let sendNames = []; //Dunno what you want to do with this functions so let's store them in an array
  for(let i = 0; i < arr.length; i++) {
    sendNames.push(sendName.bind(this, arr[i])); // this - context, later arguments
  }
	return sendNames;
}
var receivedNames = getNames();
receivedNames[1](); //b
receivedNames[3](); //d

Upvotes: 2

Related Questions