var
与 let
同样的作用,都是可以声明变量并可变的。但是,现在是不推荐使用 var
而是使用 let
var讨厌的点
var没有块级作用域
var
与 let
相比最大的区别在于 var
没有块级作用域!只有函数作用域与全局作用域!
例如:
if(){
var num = 1
console.log(num) //1
}
console.log(num) //1
var
是可以穿透 if
语句的,同理 for
语句也一样穿透!除非:
function fu(){
var num = 1
console.log(num) //1
}
console.log(num) //Errer
也就是说,var是有函数作用域的!
var可以重复声明同名的变量
是的,同名的变量不会报错,甚至还能覆盖前面的变量的值
if(){
var num = 1
console.log(num) // 1
}
var num = 2
console.log(num) // 2
变量提升
所谓的变量提升,是把在函数内或全局作用域内,凡是 var
声明的变量,都会把变量名提升到函数内的第一行,如:
function fn(){
console.log(num) //undefined
var num = 1
console.log(num) // 1
}
上面的代码可以看成如下:
function fn(){
var num;
console.log(num) // undefined
num = 1
console.log(num) // 1
}
可以看出,变量名提升了,但变量的值并没有提升,所以一开始值为 undefined
,后来执行到赋值后,才有值。
同理,在函数的最外部,也就是全局作用域,与函数变量是一样的,变量会提升到全局的第一行,值之后再赋值。
应对var没有块级作用域的办法
现在推荐使用 let
,所以该办法只存在于以前的代码,办法是创建一的立即函数,把 var
放进去即可,如:
console.log(num) // Errer
(function (){
var num;
console.log(num) // undefined
num = 1
console.log(num) // 1
})()
暂时性死区
暂时性死区:Temporal Dead Zone,简称TDZ。
与 var
的变量提升类似,但如果在 let
或 const
声明某个变量前就使用这个变量,那么就会报错,而不会像 var
一样没有报错。
而暂时性死区就是,在提前使用即将要声明的变量到开始声明的变量之间,就是暂时性死区!如
var value = "global";
(function() {
console.log(value); //TDZ开始
let value = 'local'; //TDZ结束
}());
即使外面已经声明了一个同名的变量,但是函数内的变量依旧是暂时性死区!
循环中的变量
在 var
里说过, var
没有块级区间,所以 for
语句和 if
语句是可以穿透的。那么,在 for
循环有什么特别的呢?如下:
var fun = []
for (var i = 0; i < 3; i++){
fun[i] = function() {
console.log(i)
}
}
fun[0]() // 3
按照一般想法,不是应该打印 “1 ” 才对吗?那再看看下面的对与这个代码的解决方案:
var fun = [];
for (var i = 0; i < 3; i++){
fun[i] = (function(i){
return function() {
console.log(i)
}
}(i))
}
fun[0]() // 0
原来,在一般的 for
循环语句中,因为 var
会覆盖上一次循环的 var
,最后循环结束后就只是最后一次的 var
,而上面的解决办法代码,只需要给每一次循环一个单独的作用域,这样就不会重新覆盖!
现在,最新的解决办法,只需要把 var
代替成 let
即可:
var fun = []
for (let i = 0; i < 3; i++){
fun[i] = function() {
console.log(i)
}
}
fun[0]() // 3
为什么 let
会与 var
不同?
let
在底层实现方式与 var
不同,把上面的代码看成以下会很好理解:
//伪代码
(let i = 0){
fun[0] = function() {
console.log(i)
}
}
(let i = 1){
fun[1] = function() {
console.log(i)
}
}
(let i = 2){
fun[2] = function() {
console.log(i)
}
}