【问题标题】:What does declaring default parameters in a function do under the hood?在函数中声明默认参数有什么作用?
【发布时间】:2021-07-18 11:49:29
【问题描述】:

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

我发现我很难理解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 比我的水平方式高。也许有人可以用外行的方式提供解释?谢谢!

【问题讨论】:

  • 挑剔一点:“当函数被调用时,参数代替参数”参数不代替参数,值 个参数被 分配 给参数。如果您有function example(a) { /*...*/ } 并且您有let b = 42; example(b),则a 参数获取其值的方式与a = b 赋予其值的方式完全相同。参数值的来源 (b) 和参数之间没有持续的联系。这几乎肯定是你的意思,但是...... :-)

标签: javascript function scope


【解决方案1】:

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

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

<<
    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
>>

(我使用&lt;&lt;/&gt;&gt; 分隔符而不是{/},因为范围不仅仅是块范围,它们也隔离了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 有支持和反对的争论,也有相当多的讨论,但最终决定将参数列表放在自己的范围内,以防止这种情况和其他奇怪现象。

【讨论】:

  • FWIW,我在最近的一本书 JavaScript: The New Toys 的第 3 章中详细介绍了这一点。我个人资料中的链接。
  • 这就是为什么人们可以在这里使用function greet(name, greeting, message = greeting + ' ' + name) 之类的东西:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 因为JavaScript 从左到右读取参数并开始设置param1 = "something" 然后param2 = "something else" 一个接一个所以我们可以在第三个参数中使用这两个参数?
  • @BookOfFlames - 额外的范围不是原因,但是是的,确切地说,它们是按源代码顺序处理的,所以后面的参数可以引用前面的参数,但前面的参数可以' t 参考后面的,因为那些还没有初始化。就像let name = arg0; let greeting = arg1; let message = arg2 ?? greeting + ' ' + name; 一样(除了?? 也将占据null 的右手边,但默认参数仅在arg 为undefined 时才采用该值)。
猜你喜欢
  • 2016-07-03
  • 2021-07-04
  • 1970-01-01
  • 2014-07-05
  • 1970-01-01
  • 2011-02-13
  • 1970-01-01
  • 2020-01-19
相关资源
最近更新 更多