2012-12-11 30 views
1

可能重复:
Javascript closure inside loops - simple practical example添加成员动态反对

我试图做这样的事情:

var obj = function(){ 
    var members = ['a','b','c','d','e']; 
    for(var i in members){ 
     inst[i] = function(){ 
      console.log(i); 
     } 
    } 
}; 

但是当我做:

var inst = new obj(); 
inst.a(); inst.b(); inst.c(); inst.d(); inst.e(); 

它打印出5次!另外,我可能会引用this,而不是使用我实例化对象的名称,但我无法完成这项工作。这背后的逻辑是使用websockets来生成一个API模板客户端。这是一个粗略的演示,它基本上做了相同类型的事情(逻辑上),但是我陷入了这个技术问题,并且阻碍了我的进步。

感谢

编辑

让我给完整的问题。我不想超载每个人,但这些解决方案不工作...

var SocketClient = function(config){ 
//platform specific stuff 
var self = this; 
var count = 0; 
var socket = io.connect(config.address+':'+config.port); 
var members = []; 
socket.on('method',function(data){ 
    console.log(data.name); 
    KovarApp.client[data.name] = addLogicMember(data.name); 
    console.log(KovarApp.client[data.name]); 
}); 
var addLogicMember = function(n){ 
    return function(config){ 
     var callback = null; 
     if(typeof config.callback !== 'undefined'){ 
      var callback = config.callback; 
      delete config.callback; 
     } 
     call({ 
      method: n, 
      data: config, 
      callback: callback 
     }); 
    }; 
}; 
var call = function(config){ 
    var c = count++; 
    var timer = null; 
    socket.on('reply_'+c,function(data){ 
     if(typeof config.callback === 'function'){ 
      if(timer != null){ 
       timer.clearTimeout(); 
      } 
      config.callback(data); 
      timer = setTimeout(function(){ 
       socket.removeAllListeners('reply_'+c) 
      },10000); 
     } 
    }); 
    config.data.handle = c; //make sure that the server has the handle for this function call 
    socket.emit(config.method,config.data); 
}; 

};;

服务器向客户端发出5个函数:login是第一个函数,getpatientinfo是最后一个函数。在服务器上,我将它设置为console.log每个回复。如果我调用了其中的任何函数,那么它就是console.log的getpatientinfo,因为它是它接收到的字符串,这意味着在客户端上每个函数都引用最后接收到的字符串(getpatientinfo)。我已经根据一些答案改变了它,但它仍然不起作用。套接字在这里不应该是个问题。这个问题显然是我在生成成员时的前端逻辑,因为每个成员都反映了最后添加的成员。

解决!见下文! (这不是闭幕!)

+2

你的实际问题是一个已被多次询问的范围问题(找到一个重复的,任何人?),但我想在旁边说,你不应该在数组中使用'for..in'循环。它们遍历对象的所有可枚举属性,而不仅仅是数组的所有元素。 – apsillers

+0

雅无后顾之忧。它实际上使用套接字侦听器来触发成员添加。它实际上并不循环数组;我只是想轻松演示逻辑。 –

+0

这不是重复的。该解决方案对我无效。我的功能是当从服务器调用时动态地向其自身添加成员,而不用外部循环添加函数。 –

回答

6

这就是所谓的 '封闭效应':您的每一个函数知道它应该处理名为i的变量,但在调用时将取其当前的值。

为了解决这个问题,范围i还有:

var makeMeAFunction = function(x) { 
    return function() { console.log(x); }; 
}; 
for(var i in members){ 
    inst[i] = makeMeAFunction(i); 
} 

一点题外话,它通常是一个坏主意循环访问与for...in阵列:使用forEach或者,如果你只需要支持IE8,诉诸传统的for(init; check; step)运营商。

+0

有没有办法引用'this'而不是实例化的依赖关系? –

+0

由于某些原因,这对我不起作用。我已经试过关闭了。请检查编辑。 –

+0

[Closure!=匿名函数](http://stackoverflow.com/a/111200/1229023)。 – raina77ow

1

这应该做的伎俩:

function Cn() { 
    var self = this; 
    [ 'a','b','c','d','e' ].forEach(function (name, i) { 
     self[ name ] = function() { 
      console.log(i); 
     }; 
    }); 
} 

注:ES5-shim for IE8

+3

可能值得注意的是,由于缺少对Array.forEach的支持,这在IE8或更早版本中不起作用。 – jevakallio

+0

没有快乐,检查编辑 –

1

你有一个关闭相关的问题 - 看看this为好记事。

0

发现问题了,男孩让我感觉像是一只小娃娃!

这个问题是服务器端。我这样做:

for(var i in functions){ 
      socket.on(i,function(data){functions[i](data,socket,mysql)}); //create socket listeners 
     } 

当我把它改成这样:

 socket.on('login',function(data){functions.login(data,socket,mysql);}); 
     socket.on('logout',function(data){functions.logout(data,socket,mysql);}); 
     socket.on('getVisitInfo',function(data){functions.getVisitInfo(data,socket,mysql);}); 

它的工作很大。看起来它不喜欢循环一个对象。哦,我猜是静态套接字声明!

+0

虽然你一直坚持'不参与闭包',但实际上第一个片段中的问题是_exactly_关闭问题。请参阅'socket.on(prop,callback)'中的每个回调函数(event handler)'_defined_作为知道'i'的函数(对于这个函数[i]'行),但是将使用_current_值实际调用时“我”。现在将这种情况与我的答案中描述的情况进行比较。 ) – raina77ow

+0

哈哈,你是对的! –