我通过互联网上的这个有趣的测验。
console.log((function(x, f = (() => x)){
var x;
var y = x;
x = 2;
return [x, y, f()]
})(1))
选择是:
我选择了解决方案 2 TBH,基于 x 已被重新定义,y 被声明并定义为没有值,并且 f 具有不同的范围,因此获得全局 x 内存点而不是函数 x 内存点。
但是,我在 jsbin.com 中尝试过
我发现它是解决方案 1,虽然我不确定为什么会发生这种情况,但我弄乱了函数体并删除了
var x
从函数体中,我发现响应更改为 #3,这在 x 值更改时是有意义的,因此它显示 x 和 f 为 2 和 y 为 1,这是全局声明的。但我仍然不明白为什么它显示 1 而不是未定义。
最佳答案
but still I can't get why it shows 1 instead of undefined.
不只是你。这是规范的一个深刻而黑暗的部分。 :-)
这里的关键是有两个
x
s。对真的。有参数x
, 还有变量 x
.包含表达式的参数列表(如
f
的默认值)有自己的范围,与函数体的范围分开。但在参数列表可能有表达式之前,有 var x
在具有 x
的函数中参数无效(x
仍然是参数,具有参数的值)。因此,为了保留这一点,当其中有一个带有表达式的参数列表时,会创建一个单独的变量,并且参数的值为 复制 到函数体开头的变量。这就是这种看似奇怪(不,不仅仅是看似)奇怪行为的原因。 (如果你是那种喜欢深入研究规范的人,这个复制是 FunctionDeclarationInstantiation 的第 28 步。)由于
f
的默认值,() => x
,在参数列表范围内创建,它引用参数x
,而不是变量。所以第一个解决方案,
[2, 1, 1]
是正确的,因为:2
分配给 var x
在函数体内。所以在函数的最后,var x
是 2
. 1
分配给 y
来自变量 x
之前 x
得到值 2
,所以在函数的最后,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));
...I removed var x from the function body, I found that the response changed to #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));
关于您的标题的最后说明:
declaring a variable twice in IIFE
变量只声明一次。另一件事是参数,而不是变量。区别很少重要......这是罕见的时刻之一。 :-)
关于javascript - 在 IIFE 中两次声明一个变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55560027/