为什么在函数中使用 let 声明的某些变量在另一个函数中可用,而其他变量会导致引用错误?

2022-08-30 02:30:23

我不明白为什么变量在函数内部声明时表现得如此奇怪。

  1. 在函数中,我用变量和值 10 声明firstletbc

    b = c = 10;
    

    在我显示的函数中:second

    b + ", " + c
    

    这显示了:

    10, 10
    
  2. 同样在函数 I 中,使用值 10 声明firsta

    let a = b = c = 10;
    

    但在函数中,它显示一个错误:second

    找不到变量:a

  3. 现在在函数中,我用值 20 声明:firstd

    var d = 20;
    

    但是在函数中,它显示与以前相同的错误,但变量为:secondd

    找不到变量:d

例:

function first() {
  let a = b = c = 10;
  var d = 20;
  second();
}

function second() {
  console.log(b + ", " + c); //shows "10, 10"

  try{ console.log(a); }  // Rreference error
  catch(e){ console.error(e.message) }

  try{ console.log(d); } // Reference error
  catch(e){ console.error(e.message) }
}
first()

答案 1

这是因为你实际上是在说:

c = 10;
b = c;
let a = b;

而不是你认为你在说什么,那就是:

let a = 10;
let b = 10;
let c = 10;

您会注意到,无论您向链中添加多少变量,都只会是第一个(a)导致错误的变量。

这是因为“let”将变量的作用域限定为声明它的块(或者,“本地”,或多或少意味着“在括号中”)。

如果声明一个不带“let”的变量,它将全局限定变量的作用域。

因此,在设置变量的函数中,所有内容都获取值 10(如果放置断点,则可以在调试器中看到此值)。如果您在第一个函数中放置 a,b,c 的控制台日志,一切都很好。

但是,一旦你离开该函数,第一个(a)--再次记住,从技术上讲,按照赋值的顺序,它是最后一个--“消失”(同样,如果你在第二个函数中设置断点,你可以在调试器中看到这一点),但其他两个(或者你添加的许多)仍然可用。

这是因为,“let”仅适用于(因此仅在本地作用域)链中的第一个变量 - 再次,从技术上讲,这是最后一个被声明并分配值的变量。从技术上讲,其余的在他们面前没有“让”。因此,从技术上讲,这些是全局声明的(即在全局对象上),这就是为什么它们出现在第二个函数中的原因。

试试吧:删除“let”关键字。您的所有 var 现在都将可用。

“var”具有类似的局部范围效应,但在变量如何“提升”方面有所不同,这是您绝对应该理解的,但这与您的问题没有直接关系。

(顺便说一句,这个问题会让足够多的亲JS开发人员陷入困境,使它成为一个好问题)。

强烈建议您花时间研究如何在JS中声明变量的差异:没有关键字,使用“let”和“var”。


答案 2

在函数中,变量 和 是动态创建的,不使用 或 。first()bcvarlet

let a = b = c = 10; // b and c are created on the fly

不同于

let a = 10, b = 10, c = 10; // b and c are created using let (note the ,)

它们变得隐含的全球性。这就是为什么它们可以在second()

文档

将值赋值赋给未声明的变量会在执行赋值时将其隐式创建为全局变量(它成为全局对象的属性)。

为了避免这种情况,您可以使用在使用未声明的变量时提供错误"use strict"

"use strict"; // <-------------- check this

function first() {
   /*
    * With "use strict" c is not defined.
    * (Neither is b, but since the line will be executed from right to left,
    * the variable c will cause the error and the script will stop)
    * Without, b and c become globals, and then are accessible in other functions
    */
   let a = b = c = 10;
   var d = 20;
   second();
}

function second() {
   console.log(b + ", " + c); //reference error
   console.log(a); //reference error
   console.log(d); //reference error
}

first();