【问题标题】:Values of variables in scope when using closure in JavaScript在 JavaScript 中使用闭包时范围内变量的值
【发布时间】:2017-01-08 08:58:18
【问题描述】:

您能解释一下这 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)}

前 2 个返回未定义的 b,而第 3 个返回预期值。

【问题讨论】:

  • 顺便说一句,块语句后不需要冒号,如{};
  • 在 1 和 2 中,您没有将 b 传递给 print 函数
  • 你可以把print移动到doSetTimeout里面,那么b是一个局部变量。

标签: javascript variables scope closures


【解决方案1】:

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

当您传递函数值时不会发生闭包,将 print 作为参数,它会发生在任何定义 setTimeout() 并且实际调用 print() 的地方。因此,您无法访问您认为的上下文。

在最后一个示例中,它仍然可以工作,因为您正在定义一个正在执行的函数内部的匿名函数,该函数已经知道 b 是什么,所以 b 是可用的。

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

每个函数都有一个 [[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/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-17
    • 2014-01-13
    • 1970-01-01
    • 1970-01-01
    • 2015-09-29
    相关资源
    最近更新 更多