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
as
tmp\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));
}