0

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();

3
  • 1
    What you're asking doesn't seem to make sense. You make a single call to getName() which returns a function to be called later. How can that single call have "a new binding to each of the values"? It's a single result from getName(). Maybe you could return an array of functions? Commented Dec 30, 2017 at 14:16
  • Your code wouldn't even work in strict mode, as functions are block-scoped. The sendName variable you return does not exist. Which is part of your larger problem: Your getName() returns only a single function. How would you even call different functions which point to different indices (which is the part that actually already works due to your usage of let in the loop). Commented Dec 30, 2017 at 14:24
  • Possible duplicate of JavaScript closure inside loops – simple practical example Commented Dec 30, 2017 at 14:28

5 Answers 5

2

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

Sign up to request clarification or add additional context in comments.

7 Comments

When you add a negative vote to my answer, please add a feedback in comment so I could understand what's wrong.
Why so complicated? The code where the OP creates the functions already works, only the bit with the array doesn't.
@Bergi In the other case, with the self-invoking function, you can just call alert(arr[i]), I thought that the essence of the question is how to delay the invocation to later time
What is this that you are even binding?
@charlietfl It's current's function scope/context. In this example it doesn't really matter as we're not using it directly in our sendName function, we just care about currying the parameter
|
1

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.

4 Comments

There's no point in using an IIFE here. Especially if you are going to alert immediately anyway.
@Bergi We don't know exactly the author's point and the function implementation.
@Oleksandr Then you should post a comment to inquire the details, not write an answer that makes no sense.
@Bergi You are right! Let Kshri accept an answer with a better solution, I would be more than happy to remove my own one.
1

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

2 Comments

If you had kept the let i declaration in the loop header, you wouldn't have needed the temporary l variable.
Yeah Thanks I modified the answer
1

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();

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.