varlet 同样的作用,都是可以声明变量并可变的。但是,现在是不推荐使用 var 而是使用 let

var讨厌的点

var没有块级作用域

varlet 相比最大的区别在于 var 没有块级作用域!只有函数作用域与全局作用域!

例如:

  1. if(){
  2. var num = 1
  3. console.log(num) //1
  4. }
  5. console.log(num) //1

var 是可以穿透 if 语句的,同理 for 语句也一样穿透!除非:

  1. function fu(){
  2. var num = 1
  3. console.log(num) //1
  4. }
  5. console.log(num) //Errer

也就是说,var是有函数作用域的!

var可以重复声明同名的变量

是的,同名的变量不会报错,甚至还能覆盖前面的变量的值

  1. if(){
  2. var num = 1
  3. console.log(num) // 1
  4. }
  5. var num = 2
  6. console.log(num) // 2

变量提升

所谓的变量提升,是把在函数内或全局作用域内,凡是 var 声明的变量,都会把变量名提升到函数内的第一行,如:

  1. function fn(){
  2. console.log(num) //undefined
  3. var num = 1
  4. console.log(num) // 1
  5. }

上面的代码可以看成如下:

  1. function fn(){
  2. var num;
  3. console.log(num) // undefined
  4. num = 1
  5. console.log(num) // 1
  6. }

可以看出,变量名提升了,但变量的值并没有提升,所以一开始值为 undefined ,后来执行到赋值后,才有值。

同理,在函数的最外部,也就是全局作用域,与函数变量是一样的,变量会提升到全局的第一行,值之后再赋值。

应对var没有块级作用域的办法

现在推荐使用 let ,所以该办法只存在于以前的代码,办法是创建一的立即函数,把 var 放进去即可,如:

  1. console.log(num) // Errer
  2. (function (){
  3. var num;
  4. console.log(num) // undefined
  5. num = 1
  6. console.log(num) // 1
  7. })()

暂时性死区

暂时性死区:Temporal Dead Zone,简称TDZ。

var 的变量提升类似,但如果在 letconst 声明某个变量前就使用这个变量,那么就会报错,而不会像 var 一样没有报错。

而暂时性死区就是,在提前使用即将要声明的变量到开始声明的变量之间,就是暂时性死区!如

  1. var value = "global";
  2. (function() {
  3. console.log(value); //TDZ开始
  4. let value = 'local'; //TDZ结束
  5. }());

即使外面已经声明了一个同名的变量,但是函数内的变量依旧是暂时性死区!

循环中的变量

var 里说过, var 没有块级区间,所以 for 语句和 if 语句是可以穿透的。那么,在 for 循环有什么特别的呢?如下:

  1. var fun = []
  2. for (var i = 0; i < 3; i++){
  3. fun[i] = function() {
  4. console.log(i)
  5. }
  6. }
  7. fun[0]() // 3

按照一般想法,不是应该打印 “1 ” 才对吗?那再看看下面的对与这个代码的解决方案:

  1. var fun = [];
  2. for (var i = 0; i < 3; i++){
  3. fun[i] = (function(i){
  4. return function() {
  5. console.log(i)
  6. }
  7. }(i))
  8. }
  9. fun[0]() // 0

原来,在一般的 for 循环语句中,因为 var 会覆盖上一次循环的 var ,最后循环结束后就只是最后一次的 var ,而上面的解决办法代码,只需要给每一次循环一个单独的作用域,这样就不会重新覆盖!

现在,最新的解决办法,只需要把 var 代替成 let 即可:

  1. var fun = []
  2. for (let i = 0; i < 3; i++){
  3. fun[i] = function() {
  4. console.log(i)
  5. }
  6. }
  7. fun[0]() // 3

为什么 let 会与 var 不同?

let 在底层实现方式与 var 不同,把上面的代码看成以下会很好理解:

  1. //伪代码
  2. (let i = 0){
  3. fun[0] = function() {
  4. console.log(i)
  5. }
  6. }
  7. (let i = 1){
  8. fun[1] = function() {
  9. console.log(i)
  10. }
  11. }
  12. (let i = 2){
  13. fun[2] = function() {
  14. console.log(i)
  15. }
  16. }