2014-01-26 36 views
1

我还没有对JavaScript闭包的基本理解;了解JavaScript闭包 - 将冻结变量传递给回调

我有一个关于具体的情况,或许也基本和常见的例子一个问题:

从1数到3在3秒内

见的jsfiddle这里:http://jsfiddle.net/nAh8x/

代码:

var i, 
    t; 

t = 0; 

// Case A 

for(i=1; i<=3; i++) { 
    setTimeout(function() { log(i); }, t); 
    t += 1000; 
} 

// Case B 

for(i=1; i<=3; i++) { 
    setTimeout(wrapper(i), t); 
    t += 1000; 
} 

function wrapper(i) { 
    return function() { log(i); }; 
} 

// Log utility function 

function log(msg) { 
    $('#log').append(msg + '<br />'); 
} 

案例A不起作用。

很清楚,我为什么:每里面功能的setTimeout时间被称为和访问变量,它的价值已经达到了4

案例作品。

包装(I)被称为返回

function() { log(i); }; 

和上面的返回值(函数)是里面的setTimeout发生的事情。善有善报,里面的setTimeout是完全一样的情况一个

但是这一次,我变量已经“冻结”与通话的时间值。

为什么使用包装函数让传递的值被冻结?

这并不完全清楚。

+0

Paulo,我不希望不友善,但你的开头声明需要修改。它应该是:“我*还没有*对JavaScript关闭有一个基本的理解”。你所挣扎的是基本概念,即闭包捕获它的局部变量,并继续允许内部函数访问这些变量和自由变量,即使在外部函数完成并返回之后。为了发生这种情况,必须存在对内部函数的持久引用,例如通过赋值返回的函数。 –

+0

我同意你 – Paolo

+0

Paulo,好吧,也许我稍微不友好,但你把它放在下巴上 - 对你有好处。 –

回答

1

包装函数有它自己的i,它本地作用于它。

这将在调用wrapper时收到另一个i

,如果你重写了它,因为它可能是更清楚:

function wrapper(notI) { 
    return function() { log(notI); }; 
} 
1

wrapper使用的变量i是一个已经通过(作为副本)作为正式参数wrapper。这与for循环内的那个不一样i - 您可以将该变量重命名为任何您喜欢的内容,并且代码仍然可以工作。

它被冻结,因为它具有每次最初调用wrapper时的值。

1

封闭是通过调用外部函数与变量的作用域和嵌套函数创建一个环境,

每次wrapper()被称为会有创建的每个不同的环境下面的功能

function wrapper(i) { 
    return function() { log(i); }; 
} 

这里i的值将与调用wrapper()时的值相同。每次i的值对于通过调用wrapper()外部函数产生的特定环境来说都是私有的。