Javascipt中let和var的区别

前言

  • ES6中引入了let关键字和块级作用域的概念。该博文从多方面说明let和var关键字的区别,以及ES6引进该关键字的“The Good Parts”,以及解决的一些javascript之前存在的问题。

let和var的相同点

  • let和var关键字都用于声明变量

let和var的不同点

变量作用域

  • let关键字声明的变量只在let命令所在的代码块内有效。
var x = 2;
let y = 3;
  • 上面代码中,var和let的作用域都是全局作用域,但是要注意:
    1. 在javaScript中,全局作用域是针对JavaScript环境
    2. 在HTML中,全局作用域是window对象
  • 使用var关键字声明的全局作用域变量属于window对象
  • 使用 let 关键字声明的全局作用域变量不属于 window 对象
let name = 'Aaron_hj';
//不能使用window.name访问该变量

循环作用域

var a = [];
for (var i = 0; i < 10; i++) {
     
  a[i] = function () {
     
    console.log(i);
  };
}
a[6](); // 10

上面的代码中,i是由var命令声明的,在全局范围内都有效,所以全局中只有一个i变量。每一次循环后,i的值都会发生变化,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局中的i。也就是说,数组a中每一项的i指向的都是同一个i,也就是完全循环后的i的值,也就是10;(The Bad One

  • 但如果使用let声明i,就可以解决这个问题
var a = [];
for (let i = 0; i < 10; i++) {
     
  a[i] = function () {
     
    console.log(i);
  };
}
a[6](); // 6

上面的代码中,i是由let声明的,只在for{}里有效。每次循环,都会重新创建一个i变量,所以循环内赋给数组a函数内的console.log(i),里面的i都是重新声明的。那么这里有一个问题:它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为js引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算的。
注:for循环的一个特殊之处在于:设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

重置变量

  • let不允许在相同作用域内,重复声明同一个变量
  • var可以
var x = 2;
let x = 3;//报错

let y = 4;
let y = 5;//报错

let z = 6;
let z = 7;//报错

这里不知大家会不会思考一个问题,在使用var关键字重新声明变量可能会带来问题,在块内重新声明变量也会重新声明快外的变量(The Bad There)

var x = 10;
// 这里输出 x 为 10
{
      
    var x = 2;
    // 这里输出 x 为 2
}
// 这里输出 x 为 2

let关键字就可以解决该问题,因为它只在let命令在的代码块{}生效

var x = 10;
// 这里输出 x 为 10
{
      
    let x = 2;
    // 这里输出 x 为 2
}
// 这里输出 x 为 10

变量提升

  • var命令会发生变量提升的现象,即变量可以在声明前使用,值为undefined。(The Bad Two),按一般逻辑,变量应该在声明语句后才可以使用。
  • let关键字的声明就纠正了该现象,它所声明的变量一定要在声明后使用,否则抛出错误。
// var 的情况
console.log(foo); // 输出undefined
var foo = 2;

// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;

暂时性死区

Es6中明确规定,如果区块内存在let和const命令,这个区块对这些区块对这些命令的变量,从一开始就形成了封闭作用域,不再受外部的影响。而只要是声明前,都是let的死区,这在语法上,称为“暂时性死区”

if (true) {
     
  // TDZ开始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ结束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

上面代码中,let声明变量tmp之前,都属于tmp的“死区”。注:“暂时性死区”意味着typeof不再是百分百安全的操作,因为let声明前,都是tmp的“死区”

typeof tmp; //ReferenceError
let tmp;

你可能感兴趣的:(前端开发,javascript,前端学习,javascript,typescript,es6)