你能解释一下这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/