目录
一、var关键字
1.var声明作用域
使用var操作符声明的变量会成为包含它的函数的局部变量:
function fun() {
var variable = "hello";
console.log(variable);
};
fun(); // 结果是hello
console.log(variable);
// 结果是Uncaught ReferenceError: variable is not defined
这里,variable变量是在fun函数内部定义的,调用该函数会创建这个变量并初始化值,调用过后变量随即被销毁,因此在函数外部访问会报错。
2.var声明提升
使用var操作符声明的变量会自动提升到它所在的函数作用域的顶部:
function fun() {
console.log(variable); // 在这里先访问
var variable = "hello";
}
fun(); // 结果是 undefined
之所以不会报错,是因为 ECMAScript 运行时把它看成等价于如下代码:
function fun() {
var variable;
console.log(variable);
variable = "hello";
}
fun(); // 结果是 undefined
这就是所谓的“提升”(hoist),也就是把所有变量声明(var操作符声明的)都拉到函数作用域的顶部。
3. var操作符可以重复声明同一个变量
var variable = 1;
var variable = "hello";
var variable = true;
console.log(variable); // true
二、let关键词
1.let声明作用域
let声明的范围是块级作用域 (一对{ }内)。
注意:这里就和 var 声明的作用域有区别了。
// var 声明变量
if (true) {
var variable = "hello";
console.log(variable); // hello
}
console.log(variable); // hello
// let 声明变量
if (true) {
let variable = "hello";
console.log(variable); // hello
}
console.log(variable);
// Uncaught ReferenceError: variable is not defined
let声明的变量之所以不能在if块外被引用,是因为它的作用域仅限于if块内部。
块级作用域是函数作用域的子集,因此适用于 var 的作用域限制同样也适用于 let。
2.不能在同一个块内重复声明
和var又一个区别是,let操作符不允许在同一个块作用域中重复声明变量。
let variable;
let variable; //Uncaught SyntaxError: Identifier 'variable' has already been declared
// 会报错:'variable' 已经声明过
3.暂时性死区
与var又一个很重要的区别是,let声明的变量不会在它所在的作用域中被提升,对暂时性死区可以理解为,在代码块内,使用let声明变量之前,该变量都是不可用的。
console.log(variable); // undefined var 存在变量声明提升
var variable = 1;
console.log(variable1);// 直接报错
let variable1 = 1;
4.for循环中的let声明
在 let 出现之前,for 循环定义的迭代变量会渗透到循环体外部:
for (var i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // 5
改成使用 let 之后,这个问题就消失了,因为迭代变量的作用域仅限于 for 循环块内部:
for (let i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // ReferenceError: i 没有定义
在使用 var 的时候,最常见的问题就是对迭代变量的奇特声明和修改:
for (var i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 你可能以为会输出 0、1、2、3、4
// 实际上会输出 5、5、5、5、5
之所以会这样,是因为在退出循环时,迭代变量保存的是导致循环退出的值:5。在之后执行超时逻辑时,所有的 i 都是同一个变量,因而输出的都是同一个最终值。
而在使用 let 声明迭代变量时,JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量。每个 setTimeout 引用的都是不同的变量实例,所以 console.log 输出的是我们期望的值,也就是循环执行过程中每个迭代变量的值。
for (let i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 会输出 0、1、2、3、4
三、const关键字
const 的行为与 let 基本相同(块级作用域、暂时性死区、不允许重复声明等)
1.声明并初始化
const与let 和 var 的唯一 一个重要的区别是:使用const关键字声明变量时必须要初始化值,并且不可以修改。
const variable; // 报错:Missing initializer in const declaration
// ----------------
const variable1;
variable1 = 1; // 报错:Missing initializer in const declaration
// ----------------
const variable2 = 1;
variable2 = true; // 报错: Assignment to constant variable.
// ----------------
const variable3 = 1;
console.log(variable3); // 1 正确
注意:const 声明的限制只适用于它指向的变量的引用。换句话说,如果 const 变量引用的是一个对象,那么修改这个对象内部的属性并不违反 const 的限制。
const person = {};
person.name = 'Matt'; // ok
这样是完全可以的,这里const指向的是person的地址值,改变其内部属性并不会改变其地址值。
2.不能使用const来声明迭代变量
for (const i = 0; i < 10; ++i) {} // TypeError:给常量赋值
因为迭代变量会自增,所以会报错。
不过,如果你只想用 const 声明一个不会被修改的 for 循环变量,那也是可以的。也就是说,每次迭代只是创建一个新变量。这对 for-of 和 for-in 循环特别有意义:
for (const key in {a: 1, b: 2}) {
console.log(key);
}
// a, b
for (const value of [1,2,3,4,5]) {
console.log(value);
}
// 1, 2, 3, 4, 5
本文详细探讨了JavaScript中的var、let和const关键字的差异。var声明的变量存在变量提升和作用域限制,可以重复声明;let提供块级作用域,不提升且不能在同一作用域内重复声明,还有暂时性死区;const声明常量,一旦初始化不可更改,但其指向的对象属性可以修改。在for循环中,let解决了var声明迭代变量的问题,而const不能用于声明迭代变量。
2293

被折叠的 条评论
为什么被折叠?



