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

ble*_*ent 158 javascript variable-declaration

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

  1. first我用let变量bc10声明的函数中:

    b = c = 10;
    
    Run Code Online (Sandbox Code Playgroud)

    second我显示的函数中:

    b + ", " + c
    
    Run Code Online (Sandbox Code Playgroud)

    这表明:

    10, 10
    
    Run Code Online (Sandbox Code Playgroud)
  2. 同样在first函数中,我a用值10声明:

    let a = b = c = 10;
    
    Run Code Online (Sandbox Code Playgroud)

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

    找不到变量: a

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

    var d = 20;
    
    Run Code Online (Sandbox Code Playgroud)

    但是在second函数中,它显示了与以前相同的错误,但使用了变量d

    找不到变量: d

例子:

Tim*_*zio 181

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

c = 10;
b = c;
let a = b;
Run Code Online (Sandbox Code Playgroud)

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

let a = 10;
let b = 10;
let c = 10;
Run Code Online (Sandbox Code Playgroud)

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

这是因为“让”将您的变量范围限定在您声明它的块(或“本地”,或多或少意味着“在括号中”)。

如果你声明一个没有“let”的变量,它会在全局范围内限定变量。

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

但是一旦你离开那个函数,第一个 (a)——再次记住,技术上按照赋值的顺序,它是最后一个——“消失”(同样,你可以在调试器(如果您在第二个函数中设置断点),但其他两个(或您添加的任何数量)仍然可用。

这是因为,“让”仅适用于(因此仅适用于本地范围)第一个变量——同样,这在技术上是链中最后一个被声明并赋值的变量。其余的技术上没有“让”在他们面前。所以这些在技术上是全局声明的(即在全局对象上),这就是它们出现在您的第二个函数中的原因。

试试看:删除“let”关键字。您的所有变量现在都可用。

"var" 具有类似的局部作用域效果,但在变量“提升”的方式上有所不同,这是您绝对应该理解的,但这与您的问题没有直接关系。

(顺便说一句,这个问题会难倒足够多的专业 JS 开发人员使其成为一个好问题)。

强烈建议您花时间了解在 JS 中如何声明变量的不同之处:不带关键字、带“let”和带“var”。

  • @Thevs 为什么在这个答案的上下文中你推荐“var”而不是“let”?我不明白。 (8认同)
  • 这既是编程中最好的也是最坏的事情:计算机会“完全”按照你的指令去做。不一定是您打算告诉它做什么。程序很完美。我们制造问题。 (4认同)
  • @Thevs 我强烈不同意你的观点。如果使用不慎,`var` 很容易出现错误。检查这个[小提琴](https://jsfiddle.net/gfo09w5z/) (4认同)
  • @Thevs 在什么情况下“var”比“let”有*任何*优势?让我澄清一下:现代背景下,两者都是选项,并且我要求一个“应该”编写的代码。当我之前问过这个问题时,我收到了关于“您可以使用 `var` 重新声明变量”的答案,在这种情况下,我必须提醒人们*您不应该重新声明变量*。这要么是代码逻辑中的错误,要么是错误 - 所以重新声明的好处是......它允许您编写错误的代码。当“let”也是一个选项时,我还没有看到任何支持“var”的合理理由。 (2认同)
  • 为 javascript 画上另一个分数。除非声明为局部变量,否则所有变量都是全局变量。:( (2认同)

Cid*_*Cid 69

在函数中first(),变量bc是动态创建的,无需使用varlet

let a = b = c = 10; // b and c are created on the fly
Run Code Online (Sandbox Code Playgroud)

不同于

let a = 10, b = 10, c = 10; // b and c are created using let (note the ,)
Run Code Online (Sandbox Code Playgroud)

它们变得隐式全局。这就是为什么它们可以在second()

文档

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

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

let a = b = c = 10; // b and c are created on the fly
Run Code Online (Sandbox Code Playgroud)

  • 另外: `let a = 10, b = 10, c = 10;` 或 `let a, b, c; a = b = c = 10;` 否则是声明变量的正确方法。 (16认同)
  • 赞成主要是为了“严格使用”。在面试问题的背景下,这也是我对此代码评论的开始。 (8认同)
  • @Tick20 变量“b”不会被评估/到达,错误将发生在“let a = b = c = 10;”行上,从**右到左**读取。`c` 是导致 `ReferenceError` 的第一个变量,该行的其余部分将不会被执行(脚本已停止) (2认同)
  • 像 `let a = 10, b = a, c = b;` 之类的东西也是有效的 (2认同)

fat*_*jad 24

在说奇怪之前,让我们先了解一些基础知识:

varlet都用于 JavaScript 中的变量声明。例如,

var one = 1;
let two = 2;
Run Code Online (Sandbox Code Playgroud)

也可以不使用var或来声明变量let。例如,

three = 3;
Run Code Online (Sandbox Code Playgroud)

现在上述方法之间的区别在于:

var 是函数作用域

let 是块范围的。

而没有var/let关键字声明的变量的范围变成全局变量,而不管它在哪里声明。

可以从网页的任何位置访问全局变量(不推荐,因为全局变量可能会被意外修改)。

现在根据这些概念让我们来看看有问题的代码:

 function first() {
   let a = b = c = 10;
   /* The above line means:
    let a=10; // Block scope
    b=10; // Global scope
    c=10; // Global scope
    */

   var d = 20; // Function scope
   second();
}

function second() {
   alert(b + ", " + c); // Shows "10, 10" //accessible because of global scope
   alert(a); // Error not accessible because block scope has ended
   alert(d); // Error not accessible because function scope has ended
}
Run Code Online (Sandbox Code Playgroud)

  • 抱歉,我没有这样的意图,可能存在类似的东西,因为我们可能从同一来源收集了一条信息。 (2认同)
  • 两个答案可能都包含从同一原始来源复制的内容,而没有明显的引用 - 可能是 https://www.tutorialsteacher.com/javascript/javascript-variable。抄袭的存在是显而易见的,因为从原始内容中重现了语法错误 - *“没有使用 `var` 关键字声明的变量的范围成为全局的,无论它在哪里声明”*应该是 *“范围.. . 变为“* 或 *”范围...变为“*”。使用别人的原话需要引用,无论是来自这里还是其他地方。https://meta.stackexchange.com/q/160071/211183 (2认同)

Jon*_*mes 6

使用let关键字的变量应该只在块的范围内可用,而在外部函数中不可用......

您以这种方式声明的每个变量都没有使用letor var。您在变量声明中缺少逗号。

这是不建议来声明一个变量没有var关键字。它可能会意外覆盖现有的全局变量。不使用var关键字声明的变量的范围将成为全局变量,无论它在哪里声明。可以从网页的任何位置访问全局变量。

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

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

first();
Run Code Online (Sandbox Code Playgroud)