但我仍然不明白为什么它显示 1 而不是 undefined。
不只是你。这是规范的一个深刻而黑暗的部分。 :-)
这里的关键是有两个xs。对真的。有参数x,还有变量x。
包含表达式 的参数列表(如f 的默认值)有其自己的范围 与函数体的范围分开。但在参数列表可能包含表达式之前,在带有 x 参数的函数中使用 var x 没有效果(x 仍然是参数,具有参数的值)。因此,为了保留这一点,当其中有一个带有表达式的参数列表时,会创建一个单独的变量,并将参数的值复制到函数体开头的变量中。这就是看似奇怪 (不,不仅仅是表面上)奇怪行为的原因。 (如果你是那种喜欢深入研究规范的人,这个复制是FunctionDeclarationInstantiation 的第 28 步。)
由于f的默认值() => x是在参数列表范围内创建的,它指的是参数x,而不是var。
所以第一个解决方案[2, 1, 1]是正确的,因为:
-
2 被分配给函数体中的 var x。所以在函数的最后,var x 是2。
-
1 在 x 得到值 2 之前从 var x 分配给 y,所以在函数结束时,y 是 1。
-
参数
x 的值从未改变,所以f() 在函数末尾产生1
好像代码是这样写的(我删除了不必要的括号并添加了缺少的分号):
console.log(function(param_x, f = () => param_x) {
var var_x = param_x;
var y = var_x;
var_x = 2;
return [var_x, y, f()];
}(1));
...我从函数体中去掉了var x,我发现响应变成了#3...
#3 是[2, 1, 2]。这是正确的,因为当您从函数中删除var x 时,只有一个x,参数(由参数列表中的函数体继承)。因此,将2 分配给x 会更改f 返回的参数值。
以param_x 和var_x 为例,如果您从中删除var x;,它会变成这样:
console.log(function(param_x, f = () => param_x) {
var y = param_x;
param_x = 2;
return [param_x, y, f()];
}(1));
这是原始代码的注释说明(删除了多余的括号并添加了缺少的分号):
// /---- the parameter "x"
// v vvvvvvvvvvv--- the parameter "f" with a default value
console.log(function(x, f = () => x) {
var x; // <=== the *variable* x, which gets its initial value from the
// parameter x
var y = x; // <=== sets y to 1 (x's current value)
x = 2; // <=== changes the *variable* x's value to 2
// +---------- 2, because this is the *variable* x
// | +------- 1, because this is the variable y
// | | +--- 1, because f is () => x, but that x is the *parameter* x,
// | | | whose value is still 1
// v v vvv
return [x, y, f()];
}(1));
关于您的标题的最后说明:
在 IIFE 中两次声明一个变量
变量只声明一次。另一件事是参数,而不是变量。区别很少重要......这是罕见的时刻之一。 :-)