Javascript 函数表达式到底发生了什么?

Javascript 函数表达式到底发生了什么?,javascript,ecmascript-6,Javascript,Ecmascript 6,我正在学习javascript的基础知识,只是为了刷新我的记忆。当我进入ES6并解释var和let之间的差异时,其中一个例子让我(和我的同事)头疼 “严格使用”; 让printNumTwo; for(设i=0;i我//没有定义 基于此,我想扩展原始示例,以显示变量I的保留引用,即使它是一个具有名为setNumber的setter函数的值类型的变量: (函数(){ "严格使用",; 让我们打印一个数字, 设置编号; for(设i=0;i

我正在学习javascript的基础知识,只是为了刷新我的记忆。当我进入ES6并解释varlet之间的差异时,其中一个例子让我(和我的同事)头疼

“严格使用”;
让printNumTwo;
for(设i=0;i<3;i++){
如果(i==2){
printNumTwo=函数(){
返回i;
};
}
}
log(printNumTwo());
//返回2
控制台日志(i);
//返回您正在制作和使用的“未定义i”
。闭包是一个函数,加上声明闭包的环境。编写这行代码时:

printNumTwo = function() {
  return i;
};

该函数引用了i变量。只要该函数存在,该变量就不会被垃圾收集,并且可以继续被该函数引用。它不是保存值的快照,而是保存对实际变量的引用。如果该变量发生变化,如第二个示例中所示,则引用会看到修改后的值。

当然,这是有意义的。
printNumTwo
i=2
时实例化,然后您
i++
因此
i=3

我不知道ASCII可视化是否有帮助。我就是这样想的。注意,我将循环扩展到
(I<5)
;额外的迭代可能会澄清问题

+-------------+
|printNumTwo|--------------------------
+------+------+循环开始
|for(设i=0;i<5;i++)
|                              --------------------------
|         +-------------+ \    
|         |             |  |
|| i=0 | |——丢弃
|         |             |  |
|         +-------------+ /
|
|         +-------------+ \
|| i++|
||//i=1 | |--丢弃
|         |             |  |
|         +-------------+ /
|
|         +-------------+ \
|| i++|
+------->|//i=2 | |--自'printNumTwo'起保留`
|printNumTwo | |仍然有一个引用
|i++||
+-------------+ /
+-------------+ \
|i++||
|//i=4 | |——丢弃
|             |  |
+-------------+ /
--------------------------
我++
i<5:假循环结束
`我现在不在范围之内了
--------------------------
>printNumTwo()/=>3
>我//没有定义
基于此,我想扩展原始示例,以显示变量
I
的保留引用,即使它是一个具有名为
setNumber
的setter函数的值类型的变量:

(函数(){
"严格使用",;
让我们打印一个数字,
设置编号;
for(设i=0;i<3;i++){
如果(i==2){
printNumber=函数(){
返回i;
};
setNumber=函数(值){
i=值;
}
}
}
console.log('应该是2-',printNumber());//来自您的示例
setNumber(17);//更改原始i变量的值
console.log('应该是17-',printNumber());//打印更改的值
console.log(i);//未捕获引用错误:未定义i

})();您需要了解闭包,定义闭包时每个函数都包含对封闭环境的引用,并且当变量结束时,它可以访问函数事件范围之外的每个变量。为什么您会期望不同的行为
let
使
i
在整个封闭块中可用,这两个输出很容易预测。为避免与循环边界混淆,请尝试替换独立的
i++
i=42。然后,
printNumTwo
将返回42,而不是3。这与函数表达式没有多大关系-它只是形成一个正常的闭包。理解代码行为的关键是@FZs为什么您认为这不是ES6问题?
i=3
没有范围,因为循环已经在条件
i++
增加到
i
之后结束condition@Bergi,请注意介绍文字。我认为只在
I<3
之前循环可能会引起混乱。显然,更改循环边界会导致其自身的混乱!我仍然是认真的。在使用
i=2
进行迭代后,首先循环体中的
i++
增加
i
3
,然后循环头中的
i++
增加
i
,进一步增加到
4
,循环结束。如果你使用了
i<5
,你会得到另一个
i=4
的迭代@bergi:哦,该死,当然。很抱歉这在图表中很难解释。@bergi:很好!这比为for表达式的各个部分添加了两列和标签更干净——太难看了。谢谢你的清理工作!那么为什么循环头中的
i++
不会影响闭包中的
i
?你认为“当
i=2
”确实有效时是如何实例化的?