你能解释这三段代码之间的区别吗?它们看起来与我相同,但输出结果不同。
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)}
前2个返回b为未定义,而第3个返回预期值。
答案 0 :(得分:0)
在你给出的前两个例子中,你没有将b传递给print(),所以print无法通过查看它的词法父母来找到该变量。
当您传递函数值时,闭包不会发生,以print作为参数,只要定义了setTimeout()并且实际调用了print(),它就会发生。因此,您无法访问自己认为的上下文。
在最后一个例子中它无论如何都有效,因为你定义正在执行的函数内部的匿名函数已经知道b是什么,所以b是可用的。
&#34;当给定的执行上下文遇到代码中的函数定义时,会创建一个新的函数对象,其内部属性名为[[scope]](如词法作用域),它引用当前的VariableEnvironment。 (ES 5 13.0-2)
每个函数都获得一个[[scope]]属性,并且在调用该函数时,scope属性的值被赋值给其VariableEnvironment的外部词法环境引用(或outerLex)属性。 (ES 5 10.4.3.5-7)这样,每个VariableEnvironment都继承自其词法父类的VariableEnvironment。此范围链从全局对象开始运行词法层次结构的长度。&#34;
来源:
https://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/
也很好读:
http://davidshariff.com/blog/what-is-the-execution-context-in-javascript/