“变量、作用域、闭包”的版本间差异
		
		
		
		
		
		跳到导航
		跳到搜索
		
				
		
		
	
 (创建页面,内容为“category:JavaScript  == 变量 ==        === 词法作用域 ===        == 闭包 ==    == <span style="color: green">'''一个有意思的例子'''</span> ==  一个涉及到“Event Loop”和“var 作用域”的例子。  对于以下代码: : <syntaxhighlight lang="JavaScript" highlight=""> for (var i = 0; i < 10; i++) {     setTimeout(function() { console.log(i) }, 100 * i) } </syntaxhighlight> : 是否预期输出: : <syntaxhighlight lang="bash"…”)  | 
				无编辑摘要  | 
				||
| 第2行: | 第2行: | ||
== 变量 ==  | == 变量 ==  | ||
 ECMAScript 6 中引入了 let、const。  | |||
JavaScript 有三种声明方式:  | |||
# '''var''':声明一个'''变量'''(<abbr title="在函数之外声明的变量">局部变量</abbr> / <abbr title="在函数内部声明的变量">全局变量</abbr>),初始化可选。  | |||
# '''let''':声明一个'''块作用域'''的'''局部变量''',初始化可选。  | |||
# '''const''':声明一个'''块作用域'''的'''只读常量''',必须初始化。  | |||
 局部变量 / 全局变量:只与其定义位置有关。  | |||
=== 作用域 ===  | |||
 ECMAScript 6 之前没有“块作用域”:语句块中声明的变量将成为语句块所在函数(或全局作用域)的局部变量。  | |||
# <span style="color: green">'''全局作用域'''</span>:可被当前'''文档'''中的任何其他代码所访问;  | |||
#: “全局变量”的作用域  | |||
# <span style="color: green">'''函数作用域'''</span>:可被当前'''函数'''内部的其他代码所访问;  | |||
#: “局部变量”的作用域  | |||
# <span style="color: green">'''块作用域'''</span>:可被当前'''块'''(由 '''<code>{ }</code>''' 包围)内部的其他代码所访问;  | |||
#: “局部变量”的作用域  | |||
 <span style="color: blue">'''var 变量没有“块作用域”:将会使用(块所在的)“函数作用域”或“全局作用域”'''</span>  | |||
 var 变量将透传 if、for 和其它代码块 —— 这是因为在早期的 JavaScript 中,块没有<span style="color: red">'''词法环境'''</span>  | |||
示例:  | |||
: <syntaxhighlight lang="JavaScript" highlight="">  | |||
if (true) {  | |||
    var x = 5;  | |||
}  | |||
console.log(x); // 5  | |||
if (true) {  | |||
    let y = 5;  | |||
}  | |||
console.log(y); // ReferenceError: y is not defined  | |||
</syntaxhighlight>  | |||
=== 变量提升 ===  | |||
== 词法作用域 ==  | |||
| 第89行: | 第127行: | ||
  当用let声明一个变量,它使用的是词法作用域或块作用域。  |   当用let声明一个变量,它使用的是词法作用域或块作用域。  | ||
== 参考 ==  | |||
<references/>  | |||
2023年4月15日 (六) 20:00的版本
变量
ECMAScript 6 中引入了 let、const。
JavaScript 有三种声明方式:
- var:声明一个变量(局部变量 / 全局变量),初始化可选。
 - let:声明一个块作用域的局部变量,初始化可选。
 - const:声明一个块作用域的只读常量,必须初始化。
 
局部变量 / 全局变量:只与其定义位置有关。
作用域
ECMAScript 6 之前没有“块作用域”:语句块中声明的变量将成为语句块所在函数(或全局作用域)的局部变量。
- 全局作用域:可被当前文档中的任何其他代码所访问;
- “全局变量”的作用域
 
 - 函数作用域:可被当前函数内部的其他代码所访问;
- “局部变量”的作用域
 
 - 块作用域:可被当前块(由 
{ }包围)内部的其他代码所访问;- “局部变量”的作用域
 
 
var 变量没有“块作用域”:将会使用(块所在的)“函数作用域”或“全局作用域” var 变量将透传 if、for 和其它代码块 —— 这是因为在早期的 JavaScript 中,块没有词法环境
示例:
if (true) { var x = 5; } console.log(x); // 5 if (true) { let y = 5; } console.log(y); // ReferenceError: y is not defined
变量提升
词法作用域
闭包
一个有意思的例子
一个涉及到“Event Loop”和“var 作用域”的例子。
对于以下代码:
for (var i = 0; i < 10; i++) { setTimeout(function() { console.log(i) }, 100 * i) }
- 是否预期输出:
 0 1 2 3 4 5 6 7 8 9
- 但,实际输出:
 10 10 10 10 10 10 10 10 10 10
其原因有两点:
- setTimeout 是一个任务,将在 for 所有循环完成之后执行;
 - i 由 var 定义:所有的 setTimeout 实际上都引用了“相同作用域里的同一个 i” —— 而它在所有循环之后其值为 10;
 
要与预期输出一致,有两种方式:
- 通过使用“立即执行的函数表达式”来捕获 i:
for (var i = 0; i < 10; i++) { (function(i) { setTimeout(function() { console.log(i) }, 100 * i) })(i) }
- 不能妄想通过 let、const 来捕获:
for (var i = 0; i < 10; i++) { setTimeout(function() { const v = i; console.log(i); }, 100 * i) }
 
 - 使用 let 替换 var:
for (let i = 0; i < 10; i++) { (function(i) { setTimeout(function() { console.log(i) }, 100 * i) })(i) }
 
var作用域或函数作用域 当用let声明一个变量,它使用的是词法作用域或块作用域。