MOR_SNOW
MOR_SNOW

Reputation: 831

Problems with scope

I am trying to assign a handler to every child element that I loop over. My problem is that the: target = child.items[i].id; will have the id of the last element that I loop over. So this part:

    fn: function() {
        isoNS.injectKey(target);
    }

will always have the the id (target) of the last child. How can I do this? I have tried put this in front, like this: isoNS.injectKey(this.target);

var arr=[];

for(var i = 0; i < obj.items.length; ++i) {
    target = child.items[i].id;
    arr.push({
        key: sHolder.charAt(i),
        fn: function() {
            isoNS.injectKey(target);
        },
    });
}

So my main problem, is that each different value of: target = child.items[i].id; is overwritten with the latest element each time. I hope I am making myself understood.

In case you are wondering what obj and child is... I left them out to make the code shorter and more understandable. just know that they do have values in them, and are never null

Upvotes: 1

Views: 40

Answers (3)

Jack Allan
Jack Allan

Reputation: 15004

The problem is your function is a closure and it has captured a reference to the target variable and this gets changed by your loop before the call back is invoked. A simple way to get around this is to wrap your function in another closure that captures the value of the target variable.

You can do this like so:

(function(capturedValue){
    return function () {
        // do something with the capturedValue
    };
}(byRefObject));

The first function is part of an Immediately Invoked Function Expression (IIFE). It serves to capture the value of the byRefObject. You can read more about IIFE here.

Your code could look like this:

var arr=[];

for(var i = 0; i < obj.items.length; ++i) {
    target = child.items[i].id;
    arr.push({
        key: sHolder.charAt(i),
        fn: (function(target) {
                return function() {
                    isoNS.injectKey(target);
                };
             })(target)
        },
    });
}

Upvotes: 2

Jaromanda X
Jaromanda X

Reputation: 1

You could do this

var arr = Array.prototype.map.call(obj.items, function(obj, i) {
    return {
        key: sHolder.charAt(i),
        fn: function() {
            isoNS.injectKey(child.items[i].id);
        }
    };
});

the Array map function provides the closure, and a nicer way to build up your arr

I use Array.prototype.map.call because there's no indication if obj.items is a TRUE array ... if it is, then it's a bit simpler

var arr = obj.items.map(function(obj, i) {
    return {
        key: sHolder.charAt(i),
        fn: function() {
            isoNS.injectKey(child.items[i].id);
        }
    };
});

Upvotes: 3

Tom
Tom

Reputation: 8180

This has to do with closures:

var arr=[];

function getFunc(t){ 
          return function() {
            isoNS.injectKey(t);
        }};

for(var i = 0; i < obj.items.length; ++i) {
    target = child.items[i].id;
    arr.push({
        key: sHolder.charAt(i),
        fn: getFunc(target),
    });
}

Upvotes: 1

Related Questions