在JavaScript中使用闭包时作用域中变量的值



你能解释一下这3段代码之间的区别吗?它们对我来说似乎完全一样,但输出不同。

1:

var i;
function print(){return function(){console.log(b)}};
function doSetTimeout(b){setTimeout(print(),2000);};
for(i=0;i<10;i++){doSetTimeout(i)}

2:

var i;
function print(){console.log(b)};
function doSetTimeout(b){setTimeout(print,2000);};
for(i=0;i<10;i++){doSetTimeout(i)}

3:

var i;
function doSetTimeout(b){setTimeout(function(){console.log(b)},2000);};
for(i=0;i<10;i++){doSetTimeout(i)}

前两个返回b为未定义,而第三个返回预期值。

在您给出的前两个例子中,您没有将b传递到print()中,因此print无法通过查看其词法父变量来找到该变量。

当你传递函数值时,闭包不会发生,print是一个参数,它会发生在任何定义了setTimeout()并且实际调用了print()的地方。所以你无法接触到你所认为的环境。

在最后一个例子中,它仍然有效,因为在一个已经知道b是什么的函数中定义匿名函数,所以b是可用的。

"当给定的执行上下文在代码中遇到函数定义时,会创建一个新的函数对象,该对象具有名为[[scope]]的内部属性(如词法范围),该属性引用当前的VariableEnvironment。(ES 5 13.0-2)

每个函数都有一个[[scope]]属性,当调用该函数时,scope属性的值被分配给其VariableEnvironment的外部词法环境引用(或outerLex)属性。(ES 5 10.4.3.5-7)通过这种方式,每个VariableEnvironment都继承自其词法父级的VariableEnvironment。这个作用域链接从全局对象开始运行词法层次结构的长度。">

来源:

https://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/

同样值得一读:

http://davidshariff.com/blog/what-is-the-execution-context-in-javascript/

最新更新