变量声明
js
中可以使用 var
、let
和 const
声明变量,三者的区别见下
变量提升
- var: 使用
var
声明的变量会发生变量提升,也就是把所有变量声明都拉到函数作用域的顶部,变量可以在声明之前使用,但其值为undefined
jsconsole.log(a) //undefined var a = 100 function fn() { console.log(b) //undefined var b = 100 } fn()
- let和const: 使用
let
和const
声明的变量不会在作用域中被提升,在变量声明之前访问会存在暂时性死区js//报错:Uncaught ReferenceError: Cannot access 'a' before initialization console.log(a) ❌ let a = 100
作用域
var: 使用
var
声明的变量具有函数作用域,这意味着变量在声明他的整个函数内部都是可访问的jsfunction fn() { if (true) { var a = 100 } //输出100,因为 a 在整个函数作用域内都可访问 console.log(a) } fn()
let和const: 使用
let
和const
声明的变量具有块级作用域,块级作用域用 花括号{}
定义。变量只能在声明他的块内可访问jsfunction fn() { if (true) { let a = 100 const b=100 } //报错:Uncaught ReferenceError: a is not defined // a和b只能在if块内可访问 console.log(a) ❌ } fn()
重复声明
- var: 使用
var
声明的变量可以在同一个作用域中重复声明,后面声明的变量会覆盖前面声明的jsvar a=10 var a=20 console.log(a) //20
- let和const: 在同一个作用域内,不需要重复声明同一个变量js
let a=10 //报错:Uncaught SyntaxError: Identifier 'a' has already been declared let a=20 ❌
重新赋值
- var和let:
var
和let
声明的变量可以重新赋值jsvar a=10 a=20 let b=10 b=20
- const:
const
声明的变量一旦被赋值就不能重新赋值了,但如果声明的是一个对象或者数组,可以修改其属性和元素jsconst a=10 a=20 ❌ //报错 const obj={key:20} obj.key=20 console.log(obj.key) //20
全局声明
使用 var
在 全局作用域 中声明的变量会成为window
对象的属性,let
和 const
则不会
js
var a=10
console.log(window.a) //10
let b=10
console.log(window.b) //undefined
for 循环中使用
下面这段代码会在短暂延迟后,连续输出 5 个 5。原因如下:
var
的特性: 因为var
声明的变量具有函数作用域,在下面的代码中,for
循环中的i
变量会被提升到函数作用域的顶部,在每次循环时,并不会创建新的变量i
,所有的setTimeout
回调函数实际上共享的是同一个i
变量。js
的事件循环机制:setTimeout
是一个异步函数,他会将传入的回调函数放在任务队列中,等待当前调用栈中的所有同步代码执行完成后才会执行,所以在这些回调函数执行之前,for
循环已经结束了,i
的值已经变成了5
js
for (var i = 0; i < 5; i++) {
setTimeout(() => { console.log(i) }, 0)
}
如果使用let
来声明变量 i
,则没有这个问题,因为let
具有块级作用域,每次循环都会创建一个新的变量 i
,每个 setTimeout
引用的都是不同的变量实例
js
for (let i = 0; i < 5; i++) {
setTimeout(() => { console.log(i) }, 0)
}
//依次输出 1、2、3、4、5
其他注意事项
js
for (var i = 0; i < 5; i++) {}
//输出5
console.log(i);
for (let i = 0; i < 2; i++) {}
//输出5
// 注意这个i是第一个for循序中使用var声明的i
console.log(i);
for (let j = 0; j < 5; j++) {}
//报错:j is not defined
console.log(j); ❌
区别总结
特性 | var | let | const |
---|---|---|---|
变量提升 | 存在,提升至作用域顶部并初始化为undefined✅ | 不存在❌ | 不存在❌ |
重复声明 | 允许✅ | 不允许❌ | 不允许❌ |
重新赋值 | 允许✅ | 允许✅ | 不允许,指向的引用不可变,但引用内部的数据可变❌ |
是否需要初始化 | 不需要❌ | 不需要❌ | 需要✅ |