ES6 let和const命令

let和var的区别

  1. var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined。let不存在变量提升,它所声明的变量一定要在声明后使用,否则报错。
  2. let不允许在相同作用域内重复声明同一个变量,var可以。
  3. let会产生块级作用域,且只在自己的作用域内生效,var不受限制。
  4. let存在暂时性死域。

let不允许在相同作用域内,重复声明同一个变量

var a = 1;
var a = 2;//不会报错
let b = 1;
let b = 2;//报错

let会产生块级作用域,且只在自己的作用域内生效,var不受限制

ES5 只有全局作用域和函数作用域,那什么是块级作用域?当我们在{}中使用了let或者const时,{}的范围就是一个块级作用域,此时let或const只能在{}中访问.

{
  let a = 1;
  var b = 2;
}
console.log(a);//报错
console.log(a);//2

特别注意,let与var在for循环中表现不同

//for循环用var
var a = []; 
for (var i = 0; i < 10; i++) { 
  a[i] = function () { 
    console.log(i); 
  }; 
} 
a[1]();//10
a[2]();//10
a[3]();//10
a[6](); // 10

上面代码中,变量i是var声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的function在运行时,会通过闭包读到这同一个变量i,导致最后输出的是最后一轮的i的值,也就是10。
而如果使用let,声明的变量仅在块级作用域内有效,最后输出的是6。

//for循环用let
var a = []; 
for (let i = 0; i < 10; i++) { 
  a[i] = function () { 
    console.log(i); 
  }; 
} 
a[1](); // 1
a[2](); // 2
a[3](); // 3
a[6](); // 6

上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。
另外,for循环还有一个特别之处,就是循环语句部分是一个父作用域,而循环体内部是一个单独的子作用域。在父子作用域中使用let声明同一变量时,对于此变量而言,两个作用域的同名变量其实是互不相关的两个独立变量:

for (let i = 0; i < 3; i++) { 
  let i = 'abc'; console.log(i); 
} 
// abc 
// abc 
// abc

即便父子作用域都使用了let,子作用域也能正常继承自己非let的变量,父也能读取子作用域非let的变量.

{
  let a = 1;
  {  //这里使用了let,也是块级作用域,但也能正常访问父块级作用域的变量a  let c = 1;
    var b = 2;
    console.log(a);//1  }
  console.log(a);//1
  console.log(b);//2
  }

所以下面这个循环输出了三次echo,因为在子作用域中声明的i跟父作用域中的i可以说是完全不同的两个i;

for(let i = 0;i<3;i++){
  let i = 'echo';
  console.log(i);
};//输出三次echo

但如果你将let改为var,你会发现只输出一次,因为没有了块级作用域,父子作用域共用了一个变量i,第一次循环后,子作用域的i被改为了echo,父作用域中i<3的判断无法通过,所以只输出了一次。

let不存在变量提升

var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined。
为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

console.log(a);//undefinedvar a = 1;
console.log(b);//报错
let b = 1;

var a = 1;
function f() {
  console.log(a);//undefined
  if (false) {
    var a = 2;
  }
}
f();

你肯定在想,这个地方应该输出1啊,下面的条件判断是false,都没执行,很遗憾,变量提升是声明提前,赋值在原地,条件判断管的是要不要给a赋值,声明早就提前了。这段代码等同于:

var a = 1;
function f() {
  var a;
  console.log(a);//undefined
  if (false) {
    a = 2;
  }
}
f();

let存在暂时性死域

当一个区域存在let声明时,这个区域就形成了一个封闭的作用域,在let声明前使用这个变量就会报错,也就是只能先声明再使用,这种语法也称为暂时性死域。

{
  let a = 1;
  {
    console.log(a);//报错
    let a =2;
  }
}

const声明的特点

let的特性const都有,不能反复声明,存在块级作用域,不存在变量提升,也有暂时性死域的特点。与let区别在于,const声明的是一个常量,一旦声明就无法修改,有个误区需要特别注意,举个例子:

const a = {};
a.b = 1;
console.log(a);//{b:1}

上述代码中我声明了一个常量对象a,但是a对象修改了,并没有报错,这是为什么呢?从本质上理解,const声明的变量并非变量的值不能修改,而是可以理解为变量的指向不能修改。只是基本类型的数据,键值都在栈内存中,但对于复杂数据类型,变量指向的其实是堆内存中存放值所提供的一个地址。所以我们不能修改复杂数据类型的指向,这样就会报错:

const a = {};
a.b = 1;
console.log(a);//{b:1}
a = [];//这里直接修改了变量a的指向,不允许了。
console.log(a);//报错
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值