这不是调试问题或操作方法问题。这是一个概念问题。
我发现很难把我的头裹在这个";第二范围";事情是这样的,但忽略了细节,我得出了这样的解释:
如果函数存储(以某种方式(如下:
{
// function body written using undefined parameters.
// When the function is called the arguments are assigned to the parameters.
}
声明默认参数是这样做的:
{ // Second scope
parameter1 = "something"
parameter2 = 5
{
// function body written using the above parameters.
// When the function is called the arguments or default values get assigned to the parameters.
}
}
这真的是幕后发生的事情吗?如果没有,那里面会发生什么?ECMAScript文档远远高于我的级别。也许有人可以用外行的话来解释?谢谢
这是一个很好的解释!是的,参数列表有自己的作用域。让我进一步解释一下你的解释,然后解释为什么会有额外的范围。
当您调用一个没有默认参数值的函数时,会为函数体创建一个新的作用域,并且参数会像函数中的顶级变量一样在该作用域中创建。因此,从概念上讲:
<<
let param1 = /*...the argument value provided for param 1 if any */;
let param2 = /*...the argument value provided for param 2 if any */;
// Start of function code
var variable1;
let variable2;
// End of function code
>>
(我使用<<
/>>
分隔符而不是{
/}
,因为作用域不仅仅是块作用域,它们还隔离var
;所以我选择了一个任意的分隔符。(
当有默认参数值时,正如您所描述的,还有一个额外的范围:
<<
let param1 = /*...the argument value provided for param 1 if any */;
let param2 = /*...the argument value provided for param 2 if any */;
<<
// Start of function code
var variable1;
let variable2;
// End of function code
>>
>>
原因是默认参数值是表达式,而不仅仅是文字。例如:
function example(a = 1, b = a + 1) {
// ^^^^^−−−−−−−−−−−−− expression, not just literal
return a + b;
}
console.log(example()); // 1 + (1 + 1) = 3
console.log(example(2)); // 2 + (2 + 1) = 5
重要的一个原因是,如果参数列表和函数体只有一个作用域,这意味着参数列表中的表达式可以引用函数体中声明的已提升变量和函数。提升的变量只有值undefined
,所以这不会有用,但提升的函数会用它们的函数体初始化,导致这样的情况:
// Doesn't work because of the additional scope
function example(a, b = blarg()) {
function blarg() {
return 42;
}
// ...
}
这会导致ReferenceError,因为函数体的作用域在参数列表的作用域中不可用。
IIRC有支持和反对的论点,也有相当多的讨论,但最终决定将参数列表放在自己的范围内,以防止出现这种情况和其他奇怪情况。