在函数中声明默认参数在幕后做了什么?

What does declaring default parameters in a function do under the hood?

这不是调试问题或操作方法问题。这是一道概念题。

我发现很难理解this“第二范围”是什么,但忽略了细节我想出了这个解释:

如果一个函数是这样存储的(以某种方式):

{
  // 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 docs 比我的水平高 。也许有人可以用通俗易懂的方式提供解释?谢谢!

这个解释很好!是的,参数列表有它自己的范围。让我稍微扩展一下您的解释,然后解释为什么会有额外的范围。

当您调用一个没有默认参数值的函数时,会为函数体创建一个新范围,并且在该范围内创建参数,就像函数中的顶级变量一样。所以,从概念上讲:

<<
    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 有赞成和反对的争论,也有一些讨论,但最终决定将参数列表放在它自己的范围内,以防止出现这种情况和其他奇怪情况。