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

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

  1. first函数中,我用 let声明变量 bc,值为 10:

    b = c = 10;
    

    second函数中,我显示:

    b + ", " + c
    

    这里显示:

    10, 10
    
  2. Also in first function I declare a with value 10:

    let a = b = c = 10;
    

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

    找不到变量: a

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

    var d = 20;
    

    但在 second函数中,它显示的错误与前面相同,只是变量 d:

    找不到变量: 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()

16464 次浏览

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

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();

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

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

声明一个没有 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();

那是因为你实际上在说:

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

而且不是你想说的那样,那就是:

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

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

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

如果声明一个变量时没有使用“ let”,那么它会在全局范围内作用于该变量。

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

但是一旦你离开那个函数,第一个(a)——同样,请记住,从技术上来说,它是最后一个——“消失”(同样,如果你在第二个函数中设置了断点,你可以在调试器中看到这一点) ,但是另外两个(或者无论你添加多少个)仍然可用。

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

尝试一下: 删除“ let”关键字。所有的 vars 现在都可用了。

“ var”具有类似的局部范围效应,但是在变量“悬挂”的方式上有所不同,这是您肯定应该理解的,但是与您的问题没有直接关系。

(顺便说一句,这个问题足以难倒专业的 JS 开发人员,让它成为一个好问题)。

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

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

Var 都用于 JavaScript 中的变量声明,

var one = 1;
let two = 2;

也可以在不使用 varlet的情况下声明变量,

three = 3;

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

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
}

这是因为当你不使用 let或者 var的时候,变量是动态声明的,你最好像下面这样声明。

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

主要区别在于范围规则。Var 关键字声明的变量的作用域是直接函数体(因此是函数作用域) ,而 let 变量的作用域是由{}表示的直接封闭块(因此是块作用域)。当你说

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

C 和 b 的生命周期是有趣的,但 a 只有块的生命周期,如果你试图通过引用来访问 a,它总是显示错误,但 c 和 b 是全局的,所以它们不会显示错误。您会注意到,无论您向链中添加多少变量,只有第一个(a)会导致错误。这是因为“ let”将变量作用域设置为声明它的块(或者“本地”,或多或少意味着“在括号中”)。如果你声明一个没有“ let”的变量,它将全局作用域设置变量。因此,在设置变量的函数中,所有变量的值都是10(如果你放置了一个断点,你可以在调试器中看到这一点)。如果在第一个函数中放入 a,b,c 的控制台日志,则一切正常。但是一旦你离开那个函数,第一个(a)——同样,请记住,从技术上来说,它是最后一个——“消失”(同样,如果你在第二个函数中设置了一个断点,你可以在调试器中看到这一点) ,但是另外两个(或者无论你添加多少个)仍然可用。

下面是 JavaScript 中变量声明的3个有趣的方面:

  1. Var 将变量的作用域限制为定义它的块([俄语]用于 本地范围)

  2. Let 允许块内的外部变量值为 临时重写

  3. 简单地声明一个没有 Var的变量将使 变量 global,不管它在哪里声明

下面是 让我们的一个演示,它是该语言的最新补充:

// File name:  let_demo.js


function first() {
a = b = 10
console.log("First function:    a = " + a)
console.log("First function:    a + b = " + (a + b))
}


function second() {
let a = 5
console.log("Second function:    a = " + a)
console.log("Second function:    a + b = " + (a + b))
}


first()


second()


console.log("Global:    a = " + a)
console.log("Global:    a + b = " + (a + b))

产出:

$ node let_demo.js


First function:    a = 10
First function:    a + b = 20


Second function:    a = 5
Second function:    a + b = 15


Global:    a = 10
Global:    a + b = 20

说明:

变量 B在“ 首先()”中去除,没有 var 或 let 关键字。

因此,< em > a < em > b 是全局的,因此可以在整个程序中访问。

在名为 第二个的函数中,语句 ‘ let a = 5’临时将‘ < em > a ’的值设置为‘ < em > 5 ’,仅在函数的作用域内。

在‘ 第二()’的范围之外,即在全局范围中,‘ < em > a ’的值将如前面所定义的那样。

这个奇怪的问题是由 JavaScript 中的范围规则引起的

function first() {
let a = b = c = 10; // a is in local scope, b and c are in global scope
var d = 20; // d is in local scope
second(); // will have access to b and c from the global scope
}

假设您想声明3个初始化为相同值(100)的 局部变量局部变量。您的第一个()将看起来如下。在这种情况下,second ()将不能访问任何变量,因为它们是从 本地到 first ()

function first() {
let a = 100; // a is in local scope init to 100
let b = a; // b is in local scope init to a
let c = b // c is in local scope init to b


var d = 20; // d is in local scope
second(); // will not have access a, b, c, or d
}

但是,如果您想要 全局变量,那么您的第一个()将如下所示。在这种情况下,second 可以访问所有的变量,因为它们在 全球性的范围内

function first() {
a = 100; // a is in global scope
b = a; // b is in global scope
c = b // c is in global scope


d = 20; // d is in global scope
second(); // will have access to a, b, c, and d from the global scope
}

局部变量 (又名。在声明它们的代码块中访问)。< br > A Code block 是任意{} ,其中有一行(s)代码。

  • { var,let,const 在这里可以访问整个函数} ,
  • For (){ var 在这里可以访问外部作用域,let,const 只能在这里访问} ,
  • 等等。

全局变量 (也就是在全局范围内可访问的变量)。
这些变量附加到全局对象。全局对象依赖于环境。它是浏览器中的窗口对象。

特别说明: 您可以在 JavaScript 中声明变量,而不需要使用 var,let,const 关键字。以这种方式声明的变量附加到全局对象,因此可在全局范围中访问。
a = 100 // is valid and is in global scope

一些供进一步阅读的文章: Https://www.sitepoint.com/demystifying-javascript-variable-scope-hoisting/ Https://scotch.io/tutorials/understanding-scope-in-javascript Https://www.digitalocean.com/community/tutorials/understanding-variables-scope-hoisting-in-javascript