为什么即使在参数设置为默认值的情况下,也不能使用let声明与一个函数参数同名的变量?

时间:2019-05-15 07:35:35

标签: javascript

在es2015中,使用默认参数值时,将创建一个中间作用域。因此,我假设函数主体中的let x在不同的范围内创建一个新变量。但是为什么我仍然会收到错误消息?

使用let,我得到了错误: enter image description here

但是使用var,我得到了两个不同范围的变量。为什么? enter image description here

如果没有var声明,结果将更改。 enter image description here

由于它们不在同一范围内,因此let声明不应引发错误。

3 个答案:

答案 0 :(得分:0)

  

参数的范围(一个函数的参数)是它所属的函数。

function check(param) // it has same scope as the parameters declared inside the curly braces,same like declaring variable inside curly braces
{
 let param=2; // throws error as the param is already been declared in scope (let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used.)

var param=2 ; // does'nt throw error 
console.log(param)
}
check(2)

答案 1 :(得分:0)

这与 es2015默认参数值无关,因为它的用途是为功能参数分配默认值。

功能参数(在您的情况下为 x )自动充当该特定功能的局部变量。因此变量 x 已在该函数中声明。

因此,在像 foo(7)这样的函数调用时,您只是将值7分配给变量 x (已在函数内部声明)。

如果您想在内部更改 x 的值,则可以像下面这样使用

function foo(x=2) {
    x=5;
    console.log(x); \\ x will be 5
}

即使您使用 var 关键字重新声明相同的变量名(此处为 x ),它也不会实际上重新声明(因为已经声明过)

要更好地理解,请尝试以下操作

function foo(x=2) {
    var x;
    console.log(x); \\ you may expect x to be undefined here but x will be 2 if you call like foo() or x will be 5 if you call like foo(5)
}

摘要:

var 关键字不会引发任何错误,即使您尝试重新声明与上述变量相同的变量名。

但是 let 关键字将在您尝试重新声明相同的变量时抛出错误,以避免您现在面临的此类困惑。

希望这个详细的说明对您有所帮助。

答案 2 :(得分:0)

这是一个非常有趣的问题,我将尽力给出一个真实的答案。

简短答案:正式声明和const声明放在同一环境中,var声明将导致其一个子环境并从父环境继承初始化值。

所有这些都是为了与历史记录“ trouble var”兼容,并且不引入任何新的麻烦,并且给具有默认值的形式参数一个自己的闭包(也就是说,形式参数必须具有一个独立的环境)

然后重新考虑一下:将正式声明和const声明放入同一环境中。它将很好地工作,因为我们不允许重新声明let和const。

有关详细信息,请参见ECMAScript® 2019 Language Specification: sec-functiondeclarationinstantiation

好吧,我的简短回答仅在strict = true条件下有效,但我们有一个很棒的注意:词法声明的名称不能与函数/生成器声明,形式参数或var名称相同

无论如何,这都是为了与历史记录麻烦var 兼容,并且不会引入任何新的麻烦。

  1. 如果strict为假,则
    1. 让lexEnv为NewDeclarativeEnvironment(varEnv)。
    2. 注意:非严格函数将单独的词汇Environment Record用于 顶级词汇声明,以便direct eval 确定是否由eval引入了任何var作用域声明 代码与预先存在的顶级词汇范围发生冲突 声明。严格的功能不需要这样做,因为 严格direct eval 将所有声明放入新的Environment Record
  2. 否则,让lexEnv为varEnv。
  3. 让lexEnvRec成为lexEnv的EnvironmentRecord
  4. 将calleeContext的词法环境设置为lexEnv。
  5. 让lexDeclarations成为代码的LexicallyScopedDeclarations。
  6. 对于lexDeclarations中的每个元素,请执行
    1. 注意:词法声明的名称不能与函数/生成器声明,形式参数或var名称相同。 词汇声明的名称仅在此处实例化,而不是 初始化。
    2. 对于d的BoundNames的每个元素dn,请执行
      1. 如果IsConstantDeclaration of d为true,则
      2. 执行! lexEnvRec.CreateImmutableBinding(dn,true)。
      3. 其他,
      4. 执行! lexEnvRec.CreateMutableBinding(dn,false)。