John Resig#62和#63中的JavaScript Broken Closures和Wrapper Function

时间:2011-03-25 03:03:13

标签: javascript

下面的第一个例子是来自John Resign的学习高级JavaScript http://ejohn.org/apps/learn/#62的#62。它被称为Fix the Broken Closures。例1失败了4次。示例2仅因为具有包装函数而不同,通过了4次。它是来自同一教程的示例#63

有人可以解释一下

1)为什么示例1中的i == count++失败。

2)为什么i == count++在包装函数的帮助下传递。包装器函数如何改变它以使其工作?

提前致谢。

示例1

var count = 0; 
for ( var i = 0; i < 4; i++ ) { 
  setTimeout(function(){ 
    assert( i == count++, "Check the value of i." ); 
  }, i * 200); 
}

示例2

var count = 0; 
for ( var i = 0; i < 4; i++ ) (function(i){ 
  setTimeout(function(){ 
    assert( i == count++, "Check the value of i." ); 
  }, i * 200); 
})(i);

2 个答案:

答案 0 :(得分:2)

这很简单。 由于setTimeout执行“异步”,因此循环继续运行时,无法在函数执行时告诉i的确切值。

通过使用函数包装器,有效地将调用主体视为函数,并且明确地传递i的值。

您可以通过将函数i param重命名为j或其他内容来清除这一点,并将函数的内部更新为从i到j

基本上它归结为范围

答案 1 :(得分:1)

  1. 由于i在循环中递增,因此每次调用setTimeout回调时,赔率都很高,i的值将为4.
  2. 包装器函数引入了一个新的作用域,允许参数i的值保持其值,即使循环增加了周围的i

  3. function outerScope() {
        var x = 2, y = 3;
    
        function innerScope() {
            var x = 3;
    
            // Obviously this alerts 3.
            alert(x); 
    
            // Since we have no 'y' defined, alert the value 3 from the outer scope.
            alert(y); 
        }
    
        // Introduce a new scope.
        innerScope(); 
    
        // Since we have left the inner scope x is now 2.
        alert(x); 
    
        // Obviously this alerts 3.
        alert(y); 
    }