2012-12-11 112 views
31

访问可变变量我有一些像这样的代码:如何避免关闭

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]]; 
    ... 
    }); 
} 

而且我得到了一个警告,在封闭使用tmp_id可能会导致问题,因为它是一个可变的变量。

我怎么能避免呢?我的意思是,我怎么能发送一个不变的变量回调,因为这是一个for循环,我不能改变的zlib.gzip代码?换句话说,我怎么能把一个参数传递给一个闭包呢?

+1

你怎么能避免什么?你的问题不清楚。请更具体地说明你想要的帮助。 – jfriend00

+1

我开始写回应...但它变得非常清楚,这可以使用重构:(你正在gzip同样的东西'message.receiver.length'。张贴整个事情? – brianreavis

回答

41

你需要创建一个范围,使用自动执行功能正确捕获tmp_id。这是因为整个for循环是一个范围,意味着每次都会捕获相同的变量。因此,回调将以错误的ID结束,因为temp_id的值将在调用回调之前发生改变。

我忽略(或关闭)的警告,不过,这似乎是在抱怨,由于temp_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]]; 
      ... 
     }); 
    })(); 
} 
+1

谢谢!这就是我想要的。我正在使用由JetBrains生成的'webstorm'。 – bxshi

+4

在他的代码中,他没有捕获任何变量-javascript具有函数范围,而不是范围。回调中的tmp_id变量取决于执行时间。而在你的例子中,'const'关键字并不是真的需要......'var'会做到这一点:) – brianreavis

+0

@brianreavis关于执行时间的好处。我没有注意到'gzip'会异步执行,所以函数范围是至关重要的。将编辑。我对Webstorm一无所知,但没有'const',OP仍然捕获一个可变变量(即,我可以在调用'gzip'后改变'tmp_id'),它听起来就像这是警告所抱怨的那样。 – 2012-12-11 07:36:20

10

我都面临着同样的问题,解决它稍微修改user24359的答案,通过传递id来关闭:

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); 
} 
+0

我喜欢这种方法 – rupps

2

这里user24359的伟大答案的简化。 这是解决方案:

var object = {a:1,b:2}; 

for (var y in object){ 
    (function(){const yyy = y; 
     setTimeout(function(){console.log(yyy)},3000);})(); 
} 

上面的代码记录一个B和是解决方案。 下面的代码日志B B:

var object = {a:1,b:2}; 
for (var y in object){ 

    setTimeout(function(){console.log(y)},3000); 
} 
+0

这很容易理解,谢谢 –

0

我在量角器面临同样的问题。解决它使用下面的代码 -

(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); 
0

@ user24359答案是一个很好的解决方案,但你可以简单地通过let关键字替换var关键字。

for(var id=0; 

成为

for(let id=0; 

查看详情here

编辑:正如HeribertoJuárez所说,它只适用于支持EcmaScript6的浏览器。

+1

这不会导致不支持ECMAScript6的浏览器出现问题吗? –

0
for (var id = 0; id < message.receiver.length; id++) { 
    var tmp_id = id; 
    zlib.gzip(JSON.stringify(message.json), (err, buffer) => { 
    // Something with tmp_id ... 
    }); 
} 

vartmp_id)在回调函数的上部范围是一个环路创建封闭件是应该由于var不是块作用域可以避免common mistake。正因为如此,并且因为每个闭合回路中共享相同的lexical environment创建的,该变量将始终是最后迭代值时回调函数被调用(即message.receiver.length-1作为tmp_id)。您的IDE检测到这种行为并且抱怨正确。

为了避免该警告,有几种解决方案:

  • 更换varletvarlet tmp_id = id)确保每个创建的封闭有自己的作用域在每次迭代中定义tmp_id

    for (var id = 0; id < message.receiver.length; id++) { 
        let tmp_id = id; 
        zlib.gzip(JSON.stringify(message.json), (err, buffer) => { 
        // Do something with tmp_id ... 
        }); 
    } 
    
  • 创建词汇环境每次迭代利用IIEF,如gennadi.w did

  • 使用工厂函数(createCallback)创建在每次迭代中的回调函数:

    const createCallback = tmp_id => (err, buffer) => { 
        // Do something with tmp_id ... 
    }; 
    for (var id = 0; id < message.receiver.length; id++) { 
        zlib.gzip(JSON.stringify(message.json), createCallback(id)); 
    } 
    
  • Bind在回调函数中,他们得到前置其参数变量(S):

    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)); 
    } 
    

    注:这是可能只在function秒。箭头功能(=>)不支持bind


通常,var应避免(如的ECMAScript 2015的)由于这种易出错的行为。