JavaScript中Var与Let的比较已经是老生常谈的问题了,那今天我们来聊聊这两个关键字
变量提升
首先就是变量提升了,var可以变量提升,而let不行,我认为这是个好事。
说到变量提升,我们再来聊聊function
function test() {
console.log('a')
}
test ()
function test() {
console.log('b')
}
test()
// output b b
var test = 1
function test() {
console.log('a')
}
test ()
// TypeError: test is not a function
// 等价于如下代码
var test
function test() {
console.log('a')
}
test = 1
test()
这涉及到function
和var
的变量提升的区别了,var
中的变量提升只会提升变量声明,而不会提前赋初始值,但是function
则会在提升时就指向了那个函数,所以function
显然更具迷惑性
这里可能会有人问变量提升和函数提升的先后顺序了,其实我认为谁先谁后无所谓,因为var
关键字提升时只声明不赋值,并且可以重复声明,所以不论谁先谁后,最后的表现形式都可以将function
写在后面。这点可能需要大家思考一下
块级作用域
{
var a = 1
let b = 2
}
console.log(a)
console.log(b)
// output:
// 1
// ReferenceError: b is not define
let
声明的变量只存在于块级作用域内,所以如下代码
for (let i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i)
}, 1000)
}
// output: 0123456789
为什么呢?因为每次循环变量i都不一样。不相信?我们来验证一下
let map = {}
for (let i = 0; i < 10; i++) {
map[i] = {
add() {
i++
},
print() {
console.log(i)
}
}
}
map[0].print()
map[1].print()
map[0].add()
map[0].print()
map[1].print()
// output: 0 1 1 1
我们使用闭包让这些变量不会被回收,虽然都是i
但是他们是不同的
暂时性死区
let声明的变量不允许再次声明,也不允许在声明前使用(不仅仅因为不会变量提升)
{
let a = 1
b = 2
var a = 3 // SyntaxError: Identifier 'a' has already been declared
}
{
console.log(b)
console.log(a) // a is not define
let a = 1
var b = 2
}
{
console.log(typeof b)
console.log(typeof a) // a is not define
let a = 1
}
二者在Nodejs和浏览器环境中的区别
观察如下代码在Nodejs中和浏览器中的区别
{
let a = 1
b = 2
var c = 3
debugger
}
/*
Nodejs
由于let声明的变量具有块级作用域,所以a在Block下
由于b未声明,所以默认绑定在global下
c使用了var声明,又不具有块级作用域,所以绑定在该模块Local下
*/
/*
浏览器
由于let声明的变量具有块级作用域,所以a在Block下
由于b未声明,所以默认绑定在global下,浏览器中为window
c使用了var声明,又不具有块级作用域,而浏览器中又没有模块,所以绑定在global下,浏览器中为window
*/
Nodejs中
浏览器中
d = 6
var e = 4
let f = 5
debugger
/*
Nodejs
由于d没有声明,所以默认绑定在global下
e使用var声明,所以绑定在local下
f使用let声明,也绑定在local下
*/
/*
浏览器中
由于d未声明,所以默认绑定在global下,浏览器中为window
e使用var声明,浏览器中没有模块,所以也绑定在global中,浏览器中为window
f使用let声明,而let声明的变量是不会默认绑定在global下的,所以f绑定在Script下
*/
Nodejs中
浏览器中