3

Okay so I have an object and I want to apply a callback function to all of the methods in the object. This is what I have tried so far:

var namespace = { 
  foo : 'bar', 
  foobar :  function() { console.log('call from foobar!')},
  someFunc : function() { console.log('call from someFunc!')},
  someFunc2 : function() { console.log('call from someFunc2!')}
}

var logger = {
  _callback : function () {
    console.log('call from logger!',arguments);
  }
}

for (var m in namespace) { 
  if ( namespace.hasOwnProperty(m) && (typeof namespace[m]=='function') ) {
    logger[m] = namespace[m];
    namespace[m] = function() {
      logger._callback(arguments);
      logger[m].apply(this, arguments);
    }
  }
}

namespace.foobar('foo');
namespace.someFunc('bar');
namespace.someFunc2('bar2');

This is what is getting logged to the console:

call from logger! [["foo"]]
call from someFunc2!
call from logger! [["bar"]]
call from someFunc2!
call from logger! [["bar2"]]
call from someFunc2!

As you can see, for some reason all 3 methods of namespace are outputting 'call from someFunc2! which is wrong. I'm not sure what the issue here is.. what am I doing wrong?

slinkhi
  • 947
  • 4
  • 16
  • 32
  • 2
    see http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – georg Jan 28 '14 at 01:41

2 Answers2

5

There's just one "m". The code inside that function you create in the for loop references the "live" value of "m", not a value frozen at the point the function was created. The last value it takes on is name "someFunc2", so that's the one that's called.

Step by step:

  1. You create the "namespace" and "logger" objects.
  2. The loop runs. The variable "m" takes on the successive values of the properties in the "namespace" object, and creates a new function for each relevant property of that object.
  3. At the end of the loop, "m" has the value "someFunc2".
  4. You call one of the "namespace" functions. That'll be a call to one of the functions created in the loop. That function will in turn call the "_callback" function. And now the important key point: it references a property of the "logger" object using the value of "m". What is the value of "m"? It's "someFunc2".
Pointy
  • 405,095
  • 59
  • 585
  • 614
5

Try

for (var m in namespace) { 
   if ( namespace.hasOwnProperty(m) && (typeof namespace[m]=='function') ) {
      logger[m] = namespace[m];
      (function(index){
         namespace[index] = function() {
           logger._callback(arguments);
           logger[index].apply(this, arguments);
         };
      })(m);
   }
}

otherwise the namespace[m] = function(){} will use whatever m is last

Patrick Evans
  • 41,991
  • 6
  • 74
  • 87
  • aha, thanks! i'm not sure who to give solve to.. Pointy answered first and explained the problem better, but you showed me an actual code solution D: – slinkhi Jan 28 '14 at 01:45
  • Go with pointy's since his actually explains what is going on :) – Patrick Evans Jan 28 '14 at 01:46
  • 1
    well, he did explain what was going on so i would have eventually arrived at a solution from there, but you saved me the effort of that next step, and he has a lot more rep, so +15 would mean more to you. Also you offered to let him it so I will give it to you. – slinkhi Jan 28 '14 at 01:49