Debugging 如何避免从闭包中访问可变变量
我有一些这样的代码:Debugging 如何避免从闭包中访问可变变量,debugging,node.js,closures,Debugging,Node.js,Closures,我有一些这样的代码: for(var id=0; id < message.receiver.length; id++){ var tmp_id = id; zlib.gzip(JSON.stringify(message.json), function(err, buffer){ ... pushStatusPool[message.receiver[tmp_id]] = null; // fix memory leak
for(var id=0; id < message.receiver.length; id++){
var tmp_id = id;
zlib.gzip(JSON.stringify(message.json), function(err, buffer){
...
pushStatusPool[message.receiver[tmp_id]] = null; // fix memory leak
delete pushStatusPool[message.receiver[tmp_id]];
...
});
}
for(var id=0;id
我得到一个警告,在闭包中使用tmp_id
可能会导致问题,因为它是一个可变变量
我怎么能避免呢?我的意思是,既然这是一个for循环,而且我不能更改
zlib.gzip的代码,我怎么能向回调发送一个不可变的变量呢?或者换句话说,如何将参数传递给闭包?您需要创建一个作用域,以便使用自执行函数正确捕获tmp\u id
。这是因为整个for循环是一个作用域,这意味着每次都捕获相同的变量。因此,回调将以错误的id结束,因为在调用回调之前,temp\u id
的值将发生更改
不过,我会忽略(或关闭)这个警告,它似乎在抱怨,因为temp\u id
是可变的,所以您可能会重新分配它。那有点傻。如果确实要修复它,请尝试使用const
关键字而不是var
for(var id=0; id < message.receiver.length; id++){
(function(){
const tmp_id = id;
zlib.gzip(JSON.stringify(message.json), function(err, buffer){
...
pushStatusPool[message.receiver[tmp_id]] = null; // fix memory leak
delete pushStatusPool[message.receiver[tmp_id]];
...
});
})();
}
for(var id=0;id
我也遇到了同样的问题,通过将id传递给闭包,稍微修改了user24359的答案,就解决了这个问题:
for(var id=0; id < message.receiver.length; id++){
(function(tmp_id){
zlib.gzip(JSON.stringify(message.json), function(err, buffer){
...
pushStatusPool[message.receiver[tmp_id]] = null; // fix memory leak
delete pushStatusPool[message.receiver[tmp_id]];
...
});
})(id);
}
for(var id=0;id
这里是对user24359伟大答案的简化。
这就是解决方案:
var object = {a:1,b:2};
for (var y in object){
(function(){const yyy = y;
setTimeout(function(){console.log(yyy)},3000);})();
}
上面的代码记录了a和b,这是解决方案。
以下代码记录b:
var object = {a:1,b:2};
for (var y in object){
setTimeout(function(){console.log(y)},3000);
}
我在量角器中也遇到过同样的问题。使用以下代码解决它-
(function(no_of_agents){
ptor.element.all(by.repeater('agent in agents').column('displayName')).then(function(firstColumn){
console.log(i, '>>>>>Verifying the agent Name');
var agentsSorted = sortAgentsByName();
//verify the agent name
expect(firstColumn[no_of_agents].getText()).toEqual(agentsSorted[no_of_agents].name);
//now click on the agent name link
firstColumn[no_of_agents].click();
ptor.sleep(5000);
});
})(no_of_agents);
@user24359 answer是一个很好的解决方案,但是您可以简单地用let
关键字替换var
关键字
for(var id=0;
变成
for(let id=0;
见详情
Edit:正如Heriberto Juárez所建议的,它只适用于支持EcmaScript6的浏览器。在循环中创建闭包,使var
(tmp_id
)位于回调函数的上部范围,这是一个需要避免的问题,因为var
没有块范围。因此,并且由于在循环中创建的每个闭包共享相同的值,因此在调用回调函数时,变量始终是最后一次迭代的值(即message.receiver.length-1
astmp\u id
)。您的IDE检测到这种行为并正确地进行投诉
为避免警告,有几种解决方案:
- 将
var
替换为确保每个创建的闭包在每次迭代中都定义了自己的作用域tmp\u id
:
for (var id = 0; id < message.receiver.length; id++) {
let tmp_id = id;
zlib.gzip(JSON.stringify(message.json), function(err, buffer) {
// Do something with tmp_id ...
});
}
- 回调函数上的变量,在该变量中,它们被前置到其参数:
for (var id = 0; id < message.receiver.length; id++) {
zlib.gzip(JSON.stringify(message.json), function(tmp_id, err, buffer) {
// Do something with tmp_id (passed as id) ...
}.bind(this, id));
}
for(var id=0;id
如果可能的话,自ECMAScript 2015起,应避免使用var
,因为此类行为容易出错。如何避免?你的问题不清楚。请更具体地说明你需要什么帮助。我开始写回复。。。但很明显,这可能需要重构:(您正在压缩相同的内容message.receiver.length
次。发布整个内容?谢谢!这就是我想要的。我使用的是JetBrains生产的webstorm
。在他的代码中,他没有捕获任何变量javascript具有函数作用域,而不是块作用域。回调中的tmp\u id
变量将根据不同而有所不同。)在您的示例中,const
关键字并不是真正需要的…var
会起作用:)@brianreavis关于执行时间的观点很好。我没有注意到gzip
将异步执行,因此函数范围至关重要。将进行编辑。我对Webstorm一无所知,但如果没有const
,OP仍然捕获可变变量(即,我可以在调用gzip
后更改tmp\u id
)听起来这就是警告所抱怨的。@brianreavis-不,这里的变量是可变的或不可变的,而捕获的是变量,因此与值与引用类型无关。要说明这个问题,请尝试以下方法:,并观察它在控制台中打印的内容。然后将var
更改为const
并再次运行它。这就是警告试图帮助解决的问题。我不是说变量是不可变的——我是说在这个上下文或任何上下文中,const
没有任何用处。这是一种不好的做法(它使代码与ECMAScript的其他变体不兼容)我喜欢这种方法,这不会在不支持ECMAScript 6的浏览器中造成问题吗?
for (var id = 0; id < message.receiver.length; id++) {
zlib.gzip(JSON.stringify(message.json), function(tmp_id, err, buffer) {
// Do something with tmp_id (passed as id) ...
}.bind(this, id));
}