let与var的区别

基本用法

如下代码:

  1. {
  2. let a = 10;
  3. var b = 1;
  4. }
  5. a // ReferenceError: a is not defined.
  6. b // 1

上面的代码很明显的表明,let申明的变量只在当前的代码块中有效。

var和let在for循环中的区别

  1. var a = [];
  2. for (var i = 0; i < 10; i++) {
  3. a[i] = function () {
  4. console.log(i);
  5. };
  6. }
  7. a[6](); // 10
  8. var a = [];
  9. for (let i = 0; i < 10; i++) {
  10. a[i] = function () {
  11. console.log(i);
  12. };
  13. }
  14. a[6](); // 6

这里for循环中用var申明的i是一个全局变量,当循环完后i就变成了10.所以当调用a数组中的函数打印i时,结果为10
而当改为let申明变量i时,最后打印的i就是当轮循环的值。所以每一次循环的i其实都是一个新的变量,所以最后输出的是6

另外,for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

  1. for (let i = 0; i < 3; i++) {
  2. let i = 'abc';
  3. console.log(i);
  4. }
  5. // abc
  6. // abc
  7. // abc

上面代码正确运行,输出了 3 次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。

var 和let 在变量提升上的区别

var命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined。这种现象多多少少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。
为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

  1. // var 的情况
  2. console.log(foo); // 输出undefined
  3. var foo = 2;
  4. // let 的情况
  5. console.log(bar); // 报错ReferenceError
  6. let bar = 2;

foo变量通过var申明,会发生变量提升,所以当在申明前使用时,变量foo实际上已经存在,但是没有值,所以会输出undefined
bar变量通过let申明,不会发生变量提升。这表示在声明它之前,变量bar是不存在的,这时如果用到它,就会抛出一个错误。

不允许重复声明

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

  1. // 报错
  2. function func() {
  3. let a = 10;
  4. var a = 1;
  5. }
  6. // 报错
  7. function func() {
  8. let a = 10;
  9. let a = 1;
  10. }

所以,不能在函数内部重新声明参数。

  1. function func(arg) {
  2. let arg;
  3. }
  4. func() // 报错

const 与var

基本用法

const声明一个只读的常量。一旦声明,常量的值就不能改变。

  1. const PI =3.1415;
  2. PI // 3.1415
  3. PI =3;
  4. // TypeError: Assignment to constant variable.

上面代码表明改变常量的值会报错。
const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。

  1. const foo;
  2. // SyntaxError: Missing initializer in const declaration

上面代码表示,对于const来说,只声明不赋值,就会报错。

const 同let一样 不存在变量提升,存在暂时性死区,只能在声明后后使用。同时一样的也不能重复声明

本质

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心

  1. const foo ={};
  2. // 为 foo 添加一个属性,可以成功
  3. foo.prop =123;
  4. foo.prop // 123
  5. // 将 foo 指向另一个对象,就会报错
  6. foo ={};// TypeError: "foo" is read-only

参考

https://www.bookstack.cn/read/es6-3rd/spilt.1.docs-let.md 本文是摘抄的阮一峰的es6教程文档,做一个归纳总结