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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/59931668/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 10:42:42  来源:igfitidea点击:

Why do some variables declared using let inside a function become available in another function, while others result in a reference error?

javascriptvariable-declaration

提问by bleat interteiment

I can't understand why variables act so strange when declared inside a function.

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

  1. In the firstfunction I declare with letthe variables band cwith the value 10:

    b = c = 10;
    

    In the secondfunction I show:

    b + ", " + c
    

    And this shows:

    10, 10
    
  2. Also in firstfunction I declare awith value 10:

    let a = b = c = 10;
    

    But in the secondfunction it shows an error:

    Can't find variable: a

  3. Now in the firstfunction I declare dwith value 20:

    var d = 20;
    

    But in the secondfunction it shows the same error as before, but with the variable d:

    Can't find variable: d

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

    b = c = 10;
    

    second我显示的函数中:

    b + ", " + c
    

    这表明:

    10, 10
    
  2. 同样在first函数中,我a用值10声明:

    let a = b = c = 10;
    

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

    找不到变量: a

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

    var d = 20;
    

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

    找不到变量: d

Example:

例子:

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

回答by Tim Consolazio

It's because you're actually saying:

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

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

And not what you think you are saying, which is:

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

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

You'll notice that no matter how many variables you add to your chain, it will only be the first (a) that causes the error.

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

This is because "let" scopes your variable to the block (or, "locally", more or less meaning "in the brackets") in which you declare it.

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

If you declare a variable without "let", it scopes the variable globally.

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

So, in the function where you set your variables, everything gets the value 10 (you can see this in the debugger if you put a breakpoint). If you put a console log for a,b,c in that first function, all is well.

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

But as soon as you leave that function, the first one (a)--and again, keep in mind, technically in the order of assignment, it is the last one-- "disappears" (again, you can see this in the debugger if you set a breakpoint in the second function), but the other two (or however many you add) are still available.

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

This is because, "let" ONLY APPLIES TO (so only locally scopes) THE FIRST VARIABLE--again, which is technically the last to be declared and assigned a value--in the chain. The rest technically do not have "let" in front of them. So those are technically declared globally (that is, on the global object), which is why they appear in your second function.

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

Try it: remove the "let" keyword. All your vars will now be available.

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

"var" has a similar local-scope effect, but differs in how the variable is "hoisted", which is something you should definitely understand, but which is not directly involved with your question.

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

(BTW, this question would stump enough pro JS devs to make it a good one).

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

Strongly suggest you spend time with the differences in how variables can be declared in JS: without a keyword, with "let", and with "var".

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

回答by Cid

In the function first(), variables band care created on the fly, without using varor let.

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

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

Is different than

不同于

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

They become implicit global. That's why they are available in second()

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

From documentation

文档

Assigning a value to an undeclared variable implicitly creates it as a global variable (it becomes a property of the global object) when the assignment is executed.

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

To avoid this, you can use "use strict"that will provide errors when one use an undeclared variable

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

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

回答by fatimasajjad

Before calling things strange, let's know some basics first:

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

varand letare both used for variable declaration in JavaScript. For example,

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

var one = 1;
let two = 2;

Variables can also be declared without using varor let. For example,

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

three = 3;

Nowthe difference between the above approaches is that:

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

varis function scoped

var是函数作用域

and

letis block scoped.

let是块范围的。

while the scope of the variables declared without var/letkeyword become globalirrespective of where it is declared.

Global variablescan be accessed from anywhere in the web page (not recommended because globals can be accidentally modified).

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

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

Now according to these concepts let's have a look at the code in question:

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

 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
}

回答by JonoJames

Variables using the letkeyword should only be available within the scope of the block and not available in an outside function...

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

Each variable that you are declaring in that manner is not using letor var. You are missing a comma in the variables declaration.

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

It is not recommendedto declare a variable without the varkeyword. It can accidentally overwrite an existing global variable. The scope of the variables declared without the varkeyword become global irrespective of where it is declared. Global variables can be accessed from anywhere in the web page.

这是不建议来声明一个变量没有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();

回答by Mac Rathod

It's because of when you don't use letor varthen variable is getting declare on the fly, better you declare like following.

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

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

回答by Funwie

The strange issue is caused by scoping rules in JavaScript

奇怪的问题是由 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
}

Assuming that you want to declare 3 local variablesinitialised to the same value (100). Your first() will look like below. In this case, second() will not have access to any of the variables because they are localto first()

假设您要声明 3 个初始化为相同值 (100) 的局部变量。您的 first() 将如下所示。在这种情况下, 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
}

However, if you want global variablesthen your first() will look like below. In this case, second will have access to all the variables because they are in globalscope

但是,如果您想要全局变量,那么您的 first() 将如下所示。在这种情况下, 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
}

Local variables(aka. accessible in the code block where they are declared).
A Code block is any {} with line(s) of code between.

局部变量(又名。可在声明它们的代码块中访问)。
代码块是任何 {} 之间的代码行。

  • function() {var, let, const in here is accessible to entire function},
  • for() {var in here is accessible to outer scope, let, const accessible only in here},
  • etc.
  • function() {var, let, const 在这里可以被整个函数访问},
  • for() {var in here 可被外部作用域访问,let,const 仅可在此处访问},
  • 等等。

Global variables(aka accessible in the global scope).
These variables are attached to the global object. The global object is environment dependent. It is the window object in browsers.

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

Special note:You can declare variables in JavaScript without using the var, let, const keywords. A variable declared this way is attached to the global object, therefore accessible in the global scope.
a = 100 // is valid and is in global scope

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

Some articles for further reading: https://www.sitepoint.com/demystifying-javascript-variable-scope-hoisting/https://scotch.io/tutorials/understanding-scope-in-javascripthttps://www.digitalocean.com/community/tutorials/understanding-variables-scope-hoisting-in-javascript

进一步阅读一些文章: 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

回答by Muhammad Fahad

Main difference is scoping rules. Variables declared by var keyword are scoped to the immediate function body (hence the function scope) while let variables are scoped to the immediate enclosing block denoted by { } (hence the block scope). And when you say

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

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

c and b have the life span as fun have but a only have block span and if you try to access a by referencing it always show error but c and b are globally so they don't.You'll notice that no matter how many variables you add to your chain, it will only be the first (a) that causes the error.This is because "let" scopes your variable to the block (or, "locally", more or less meaning "in the brackets") in which you declare it.If you declare a variable without "let", it scopes the variable globally.So, in the function where you set your variables, everything gets the value 10 (you can see this in the debugger if you put a break-point). If you put a console log for a,b,c in that first function, all is well.But as soon as you leave that function, the first one (a)--and again, keep in mind, technically in the order of assignment, it is the last one-- "disappears" (again, you can see this in the debugger if you set a break-point in the second function), but the other two (or however many you add) are still available.

c 和 b 的生命周期很有趣,但 a 只有块跨度,如果您尝试通过引用访问 a,它总是会显示错误,但 c 和 b 是全局的,因此它们不会。您会注意到,无论有多少您添加到链中的变量,它只会是导致错误的第一个 (a)。这是因为“让”将您的变量范围限定为块(或者,“本地”,或多或少意味着“在括号中”)你在其中声明它。如果你声明一个没有“let”的变量,它会全局范围内的变量范围。所以,在你设置变量的函数中,所有的东西都得到值 10(如果你把一个断点)。如果你把 a,b,c 的控制台日志放在第一个函数中,一切都很好。但是一旦你离开那个函数,第一个 (a)——再次,记住,

回答by Gopinath

Here are the 3 interesting aspects of variable declarations in JavaScript:

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

  1. varrestricts the scope of variable to the block in which it is defined. ('var'is for local scope.)

  2. letallows temporary overridingof an external variable's value inside a block.

  3. Simply declaring a variable without varor letwill make the variable global, regardless of where it is declared.

  1. var将变量的范围限制在定义它的块中。('var'用于本地范围。)

  2. let允许临时覆盖块内外部变量的值。

  3. 简单地声明一个没有varlet的变量将使变量成为全局变量,而不管它在哪里声明。

Here is a demo of let, which is the latest addition to the language:

这是let 的一个演示,它是该语言的最新成员:

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

Output:

输出:

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

Explanation:

解释:

The variables aand bwere delcared inside 'first()', without var or let keywords.

变量ab被声明在“ first()”中,没有 var 或 let 关键字。

Therefore, aand bare global, and hence, are accessible throughout the program.

因此,ab是全局的,因此可以在整个程序中访问。

In function named 'second', the statement 'let a = 5'temporarily sets the value of 'a' to '5', within the scope of the function only.

在名为'second' 的函数中,语句'let a = 5'临时将 ' a'的值设置为 ' 5',仅在函数范围内。

Outside the scope of 'second()', I.E., in the global scope, the value of 'a' will be as defined earlier.

在' second()'的范围之外,IE,在全局范围内,' a'的值将与之前定义的一样。