定义
var
声明一个变量,可选地将其初始化为一个值。var定义let
声明一个块级作用域的本地变量,并且可选的将其初始化为一个值。let定义const
常量是块级作用域,很像使用 let 语句定义的变量。常量的值不能通过重新赋值来改变,并且不能重新声明。const定义
var与let
let声明的不提升(hoisting)
使用var
声明变量,变量会发生提升。打印i
,会显示i
已被声明但无赋值。
而使用let
声明变量,变量不会发生提升。打印j
,会显示j
没有被声明。1
2
3
4console.log(i); //undefined
var i
console.log(j); //Uncaught ReferenceError: j is not defined
let j
同一作用域let不能重复定义同一变量
1 | var i = 1; |
let在作用域后消失
使用let
声明的变量只在作用域内有效,作用域之后变量即消失1
2
3
4
5
6
7
8if (true) {
var i = 1;
let j = 0;
console.log(i); //1
console.log(j); //0
}
console.log(i); //1
console.log(j); //Uncaught ReferenceError: j is not defined
let的暂时性死区
如果区块中存在let和const命令,则这个区块对这些命令声明的变量从一开始就形成了封闭做作用域,只要在声明之前做任何使用,都会报错。这在语法上称为“暂时性死区”(temporal dead zone ,简称TDZ)。1
2
3
4
5var i = 1;
if (true) {
console.log(i); //Uncaught ReferenceError: i is not defined
let i = 2;
}
let声明的全局变量不属于顶层对象的属性
1 | var i = 1; |
const
const定义的常量,必须赋值
1 | const i; //Uncaught SyntaxError: Missing initializer in const declaration |
其他属性同let
- 同一作用域const不能重复定义同一变量
- const在作用域后消失
- const的暂时性死区
- const声明的全局变量不属于顶层对象的属性
let在for循环中的使用
1 | var a = []; |
变量
i
是var
命令声明的,在全局范围内都有效,所以全局只有一个变量i
。每一次循环,变量i
的值都会发生改变,而循环内被赋给数组a
的函数内部的console.log(i)
,里面的i
指向的就是全局的i
。也就是说,所有数组a
的成员里面的i
,指向的都是同一个i
,导致运行时输出的是最后一轮的i
的值,也就是5。
1 | var a = []; |
变量
i
是let
声明的,当前的i
只在本轮循环有效,所以每一次循环的i
其实都是一个新的变量,所以最后输出的是3
。你可能会问,如果每一轮循环的变量i
都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i
时,就在上一轮循环的基础上进行计算。
1 | for (var i = 0; i < 5; i++) { |
在setTimeout执行时,匿名函数function(){console.log(i);}
会查找当前运行环境中变量的值。var
声明的变量i
为全局变量,匿名函数中的i
均指向的是这个全局的i
所以会打印5 5 5 5 5。但是let
声明的变量i
只在当前运行环境有效,其值是每一个循环创建匿名函数时候的新的变量i
,但这个变量会在上一轮循环的基础上进行计算。所以会打印1 2 3 4 5。
引用来源:阮一峰. ECMAScript6入门