var 与 let 同样的作用,都是可以声明变量并可变的。但是,现在是不推荐使用 var 而是使用 let
var讨厌的点
var没有块级作用域
var 与 let 相比最大的区别在于 var 没有块级作用域!只有函数作用域与全局作用域!
例如:
if(){var num = 1console.log(num) //1}console.log(num) //1
var 是可以穿透 if 语句的,同理 for 语句也一样穿透!除非:
function fu(){var num = 1console.log(num) //1}console.log(num) //Errer
也就是说,var是有函数作用域的!
var可以重复声明同名的变量
是的,同名的变量不会报错,甚至还能覆盖前面的变量的值
if(){var num = 1console.log(num) // 1}var num = 2console.log(num) // 2
变量提升
所谓的变量提升,是把在函数内或全局作用域内,凡是 var 声明的变量,都会把变量名提升到函数内的第一行,如:
function fn(){console.log(num) //undefinedvar num = 1console.log(num) // 1}
上面的代码可以看成如下:
function fn(){var num;console.log(num) // undefinednum = 1console.log(num) // 1}
可以看出,变量名提升了,但变量的值并没有提升,所以一开始值为 undefined ,后来执行到赋值后,才有值。
同理,在函数的最外部,也就是全局作用域,与函数变量是一样的,变量会提升到全局的第一行,值之后再赋值。
应对var没有块级作用域的办法
现在推荐使用 let ,所以该办法只存在于以前的代码,办法是创建一的立即函数,把 var 放进去即可,如:
console.log(num) // Errer(function (){var num;console.log(num) // undefinednum = 1console.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)}}
