2

I have a function that duplicates a map containing key:function pairs, wrapping each function with a calling funcion.

function duplicateFunctionsMap(functionsMap){

    var newMap = {};

    for (var name in functionsMap){

        var originalFunc = functionsMap[name];

        newMap[name] = function(){
            originalFunc();
        }
    }

    return  newMap;
}

now trying to run any of the entries in the duplicated map turns out always calling the last one

duplicateFunctionsMap({
                      first: function(){alert("first");}, 
                       last: function(){alert("last");}
                      })["first"](); // outputs "last"
Barak
  • 1,148
  • 7
  • 13

4 Answers4

3

You have to introduce a scope to prevent originalFunc from changing. Functions introduce a new scope, but for loops do not:

for (var name in functionsMap){
    (function(originalFunc) {
        newMap[name] = function(){
            originalFunc();
        }; // <-- add semicolon at end of expression, too
    })(functionsMap[name]);
}
pimvdb
  • 151,816
  • 78
  • 307
  • 352
2

There is nine million duplicates on this but here it goes.. javascript doesn't have a block level scope. Repeat that.

So it becomes:

function duplicateFunctionsMap(functionsMap) {

    var newMap = {};

    for (var name in functionsMap) {
         var originalFunc = functionsMap[name];

        newMap[name] = (function (originalFunc) {
            return function () {
            originalFunc();
            };
        })(originalFunc);

    }

    return newMap;
}

Note that if you want to duplicate functions that use context, arguments and return values you need to do this:

newMap[name] = (function (originalFunc) {
    return function () {
        return originalFunc.apply(this, arguments);
    };
})(originalFunc);

Otherwise your duplicate function loses all that good stuff.

Esailija
  • 138,174
  • 23
  • 272
  • 326
0

inside your for cycle you've probably created a closure. try this code that creates an inner anonymous immediately executed function

for (var name in functionsMap){
    (function(_of) { 
        newMap[name] =  _of;
    }(functionsMap[name]))
}

See also javascript closure immediate evaluation

Community
  • 1
  • 1
Fabrizio Calderan
  • 120,726
  • 26
  • 164
  • 177
0

The other answers on this page are correct. But for a detailed explanation on why see my answer to a previously related question:

Please explain the use of JavaScript closures in loops

Community
  • 1
  • 1
slebetman
  • 109,858
  • 19
  • 140
  • 171