3

I have a little problem with one of my javascript code. Here is the code

//assume array is an array containing strings and myDiv, some div in my doc
for(var i in array) {
    var myString = array[i];
    var a = document.createElement('a');
    a.innerHTML = myString;
    a.addEventListener("click", function() {myFunc(myString)}, false);
    myDiv.appendChild(a)
}
function myFunc(s) {alert(s);}

However, since Strings are passed by reference in JavaScript, I see always the last string of my array when I click on the link a in question. Thus, my question is "How can I pass myString by value ?". Thank you for your help ! Phil

4
  • 4
    never iterate over an array using for...in. Commented Aug 13, 2012 at 15:11
  • MY EYES addEventListener allows you to delegate an event, rather then binding it to each and every element individually, you're doing both and therefore neither: the worst of two worlds... + addEventListener isn't supported by IE <9 Commented Aug 13, 2012 at 15:18
  • @EliasVanOotegem you're right about the delegation, although using a delegated handler still leaves him with the problem of how to find the appropriate data for the target of the event. Commented Aug 13, 2012 at 15:19
  • I know, that's why I merely commented your solution would be my suggestion. With IE<9 supported: if (a.addEventListener){a.addEventlistener('click',make_callback(myString),false);} else { a.attachEvent('onclick',make_callback(myString));} Commented Aug 13, 2012 at 15:29

3 Answers 3

2

You should add a closure around your event handler:

JavaScript closure inside loops – simple practical example

a.addEventListener("click", function (s) {
    return function () {
        alert(s)
    };
}(myString), false);

Also, you should not use for...in loops on arrays.

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

Comments

2

Primitive variables are not passed by reference in Javascript.

This is the classic 'loop variable called inside a closure' problem.

Here's one commonly-used solution to that problem:

for (var i = 0, n = array.length; i < n; ++i) {
    var myString = array[i];
    var a = document.createElement('a');
    a.innerHTML = myString;
    a.addEventListener("click", make_callback(myString), false);
    myDiv.appendChild(a)
}

function make_callback(s) {
     return function() {
         alert(s);
     }
}

Note that this isn't particularly memory efficient since it creates a new function scope for every element in the array.

A better solution might be to store the variable data actually on the element (i.e. as a new property) and retrieve that in the callback. In fact you're already storing that string in the .innerHTML property so you could just read that and then take advantage of delegation to register just the one handler on the elements' parent:

for (var i = 0, n = array.length; i < n; ++i) {
    var a = document.createElement('a');
    a.innerHTML = array[i];
    myDiv.appendChild(a)
}

myDiv.addEventListener('click', function(ev) {
    alert(ev.target.innerHTML);
}, false);

Comments

-1

try this : i think its always good not practice to iterate array using for...in

for(var i=0; i<array.length;i++) {
    var myString = array[i];
    var a = document.createElement('a');
    a.innerHTML = myString;
    a.addEventListener("click", function() {myFunc(myString)}, false);
    myDiv.appendChild(a)
}
function myFunc(s) {alert(s);}

1 Comment

this is a good change, but it does nothing to address the problem he's looking to solve.

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.