为什么在函数内部使用 let 声明的某些变量在另一个函数中可用,而其他变量会导致引用错误?
Why do some variables declared using let inside a function become available in another function, while others result in a reference error?
我不明白为什么变量在函数内部声明时表现如此奇怪。
在 first
函数中,我用 let
声明变量 b
和 c
的值为 10:
b = c = 10;
在我显示的second
函数中:
b + ", " + c
这表明:
10, 10
同样在 first
函数中,我声明 a
的值为 10:
let a = b = c = 10;
但是在second
函数中显示错误:
Can't find variable: a
现在在 first
函数中,我声明 d
的值为 20:
var d = 20;
但是在 second
函数中它显示了与以前相同的错误,但是变量 d
:
Can't find variable: 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()
在函数 first()
中,变量 b
和 c
是动态创建的,没有使用 var
或 let
。
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()
中可用的原因
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.
为避免这种情况,您可以使用 "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
关键字的变量应该只在块的范围内可用,在外部函数中不可用...
您以这种方式声明的每个变量都没有使用 let
或 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();
这是因为你实际上是在说:
c = 10;
b = c;
let a = b;
而不是你认为你在说什么,它是:
let a = 10;
let b = 10;
let c = 10;
您会注意到,无论您向链中添加多少变量,都只会是第一个 (a) 导致错误。
这是因为 "let" 将您的变量范围限定在您声明它的块(或者,"locally",或多或少意味着 "in the brackets")。
如果你声明一个没有 "let" 的变量,它会在全局范围内限定该变量。
因此,在您设置变量的函数中,所有内容的值都为 10(如果放置断点,您可以在调试器中看到这一点)。如果您在第一个函数中放置 a、b、c 的控制台日志,一切都很好。
但是一旦你离开那个函数,第一个 (a)——再次记住,从技术上讲,按照分配的顺序,它是最后一个——"disappears"(再次,如果您在第二个函数中设置断点,您可以在调试器中看到它),但其他两个(或无论您添加多少)仍然可用。
这是因为,"let" 仅适用于(因此仅在局部范围内)链中的第一个变量——同样,从技术上讲,这是最后一个声明并赋值的变量。其余的在技术上没有 "let" 在他们面前。所以这些在技术上是全局声明的(即在全局对象上),这就是它们出现在您的第二个函数中的原因。
试一试:删除 "let" 关键字。您所有的变量现在都可用。
"var" 具有类似的局部范围效果,但变量 "hoisted" 的方式不同,这是您绝对应该理解的,但与您的问题没有直接关系。
(顺便说一句,这个问题会让足够多的专业 JS 开发者感到困惑,无法让它成为一个好的问题)。
强烈建议您花点时间了解在 JS 中变量声明方式的差异:没有关键字、使用 "let" 和使用 "var"。
在说奇怪之前,让我们先了解一些基础知识:
var和let都用于JavaScript中的变量声明。例如,
var one = 1;
let two = 2;
变量也可以在不使用 var
或 let
的情况下声明。例如,
three = 3;
现在上述方法的区别在于:
var
是函数作用域
和
let
是块范围的。
while the scope of the variables declared without var
/let
keyword
become global irrespective of where it is declared.
Global variables can be accessed from anywhere in the web page (not recommended because globals can be accidentally modified).
现在根据这些概念来看一下有问题的代码:
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 的生命周期与 fun 一样,但 a 仅具有块跨度,如果您尝试通过引用访问 a,它总是会显示错误,但 c 和 b 是全局的,因此它们不会't.You'您会注意到,无论您向链中添加多少变量,它只会是导致 error.This 的第一个 (a),因为 "let" 将您的变量范围限定在块中(或者,"locally",或多或少的意思是 "in the brackets"),你在其中声明 it.If 你声明一个没有 "let" 的变量,它限定了变量 globally.So,在你设置你的函数中变量,所有值都为 10(如果放置断点,您可以在调试器中看到这一点)。如果您在第一个函数中放置 a、b、c 的控制台日志,那么一旦您离开该函数,所有内容都是 well.But,第一个 (a)——再次记住,从技术上讲,赋值顺序,它是最后一个——"disappears"(同样,如果你在第二个函数中设置断点,你可以在调试器中看到它),但其他两个(或者你添加的数量)仍然可用。
以下是 JavaScript 中变量声明的 3 个有趣方面:
var 将变量的范围限制在定义它的块中。 ('var' 用于 本地范围 .)
让允许临时覆盖 块内外部变量的值。
简单地声明一个没有 var 或 let 的变量将使
全局变量,无论它在哪里声明。
下面是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))
输出:
$ 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
解释:
变量a和b在'first()'中定义,没有var 或 let 关键字。
因此,a和b是全局的,因此可以在整个程序中访问。
在名为'second'的函数中,语句'let a = 5'临时将'a'的值设置为'5',仅在函数范围内。
在'second()'的范围之外,即在全局范围内,'a[=75的值=]' 将如前所述。
这个奇怪的问题是由 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)。您的 first() 将如下所示。在这种情况下,second() 将无法访问任何变量,因为它们是 local 到 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
}
但是,如果您想要全局变量,那么您的 first() 将如下所示。在这种情况下,second 将可以访问所有变量,因为它们在 global scope
中
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
}
局部变量(又名。可在声明它们的代码块中访问)。
代码块是任何带有代码行的{}之间。
- function() {这里的var, let, const是整个函数都可以访问的},
- for() {这里的 var 可以被外部作用域访问,let, const 只能在这里访问},
- 等
全局变量(又名在全局范围内可访问)。
这些变量附加到全局对象。全局对象依赖于环境。它是浏览器中的 window 对象。
特别说明:您可以在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
我不明白为什么变量在函数内部声明时表现如此奇怪。
在
first
函数中,我用let
声明变量b
和c
的值为 10:b = c = 10;
在我显示的
second
函数中:b + ", " + c
这表明:
10, 10
同样在
first
函数中,我声明a
的值为 10:let a = b = c = 10;
但是在
second
函数中显示错误:Can't find variable:
a
现在在
first
函数中,我声明d
的值为 20:var d = 20;
但是在
second
函数中它显示了与以前相同的错误,但是变量d
:Can't find variable:
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()
在函数 first()
中,变量 b
和 c
是动态创建的,没有使用 var
或 let
。
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()
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.
为避免这种情况,您可以使用 "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
关键字的变量应该只在块的范围内可用,在外部函数中不可用...
您以这种方式声明的每个变量都没有使用 let
或 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();
这是因为你实际上是在说:
c = 10;
b = c;
let a = b;
而不是你认为你在说什么,它是:
let a = 10;
let b = 10;
let c = 10;
您会注意到,无论您向链中添加多少变量,都只会是第一个 (a) 导致错误。
这是因为 "let" 将您的变量范围限定在您声明它的块(或者,"locally",或多或少意味着 "in the brackets")。
如果你声明一个没有 "let" 的变量,它会在全局范围内限定该变量。
因此,在您设置变量的函数中,所有内容的值都为 10(如果放置断点,您可以在调试器中看到这一点)。如果您在第一个函数中放置 a、b、c 的控制台日志,一切都很好。
但是一旦你离开那个函数,第一个 (a)——再次记住,从技术上讲,按照分配的顺序,它是最后一个——"disappears"(再次,如果您在第二个函数中设置断点,您可以在调试器中看到它),但其他两个(或无论您添加多少)仍然可用。
这是因为,"let" 仅适用于(因此仅在局部范围内)链中的第一个变量——同样,从技术上讲,这是最后一个声明并赋值的变量。其余的在技术上没有 "let" 在他们面前。所以这些在技术上是全局声明的(即在全局对象上),这就是它们出现在您的第二个函数中的原因。
试一试:删除 "let" 关键字。您所有的变量现在都可用。
"var" 具有类似的局部范围效果,但变量 "hoisted" 的方式不同,这是您绝对应该理解的,但与您的问题没有直接关系。
(顺便说一句,这个问题会让足够多的专业 JS 开发者感到困惑,无法让它成为一个好的问题)。
强烈建议您花点时间了解在 JS 中变量声明方式的差异:没有关键字、使用 "let" 和使用 "var"。
在说奇怪之前,让我们先了解一些基础知识:
var和let都用于JavaScript中的变量声明。例如,
var one = 1;
let two = 2;
变量也可以在不使用 var
或 let
的情况下声明。例如,
three = 3;
现在上述方法的区别在于:
var
是函数作用域
和
let
是块范围的。
while the scope of the variables declared without
var
/let
keyword become global irrespective of where it is declared.Global variables can be accessed from anywhere in the web page (not recommended because globals can be accidentally modified).
现在根据这些概念来看一下有问题的代码:
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 的生命周期与 fun 一样,但 a 仅具有块跨度,如果您尝试通过引用访问 a,它总是会显示错误,但 c 和 b 是全局的,因此它们不会't.You'您会注意到,无论您向链中添加多少变量,它只会是导致 error.This 的第一个 (a),因为 "let" 将您的变量范围限定在块中(或者,"locally",或多或少的意思是 "in the brackets"),你在其中声明 it.If 你声明一个没有 "let" 的变量,它限定了变量 globally.So,在你设置你的函数中变量,所有值都为 10(如果放置断点,您可以在调试器中看到这一点)。如果您在第一个函数中放置 a、b、c 的控制台日志,那么一旦您离开该函数,所有内容都是 well.But,第一个 (a)——再次记住,从技术上讲,赋值顺序,它是最后一个——"disappears"(同样,如果你在第二个函数中设置断点,你可以在调试器中看到它),但其他两个(或者你添加的数量)仍然可用。
以下是 JavaScript 中变量声明的 3 个有趣方面:
var 将变量的范围限制在定义它的块中。 ('var' 用于 本地范围 .)
让允许临时覆盖 块内外部变量的值。
简单地声明一个没有 var 或 let 的变量将使 全局变量,无论它在哪里声明。
下面是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))
输出:
$ 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
解释:
变量a和b在'first()'中定义,没有var 或 let 关键字。
因此,a和b是全局的,因此可以在整个程序中访问。
在名为'second'的函数中,语句'let a = 5'临时将'a'的值设置为'5',仅在函数范围内。
在'second()'的范围之外,即在全局范围内,'a[=75的值=]' 将如前所述。
这个奇怪的问题是由 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)。您的 first() 将如下所示。在这种情况下,second() 将无法访问任何变量,因为它们是 local 到 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
}
但是,如果您想要全局变量,那么您的 first() 将如下所示。在这种情况下,second 将可以访问所有变量,因为它们在 global scope
中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
}
局部变量(又名。可在声明它们的代码块中访问)。
代码块是任何带有代码行的{}之间。
- function() {这里的var, let, const是整个函数都可以访问的},
- for() {这里的 var 可以被外部作用域访问,let, const 只能在这里访问},
- 等
全局变量(又名在全局范围内可访问)。
这些变量附加到全局对象。全局对象依赖于环境。它是浏览器中的 window 对象。
特别说明:您可以在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