const

const 意为常量,常量的值不能通过重新赋值来改变,并且不能重新声明

  1. const number = 42;
  2. number = 99 // error: invalid assignment to const `number'
  3. let number = 66 // error: redeclaration of const `number`

描述

const声明创建一个值的只读引用,但这并不意味着它所持有的值是不可变的,只是变量标识符不能重新分配。例如,在引用内容是对象的情况下,这意味着可以改变对象的内容(比如,其参数)

  1. // 注意: 常量在声明的时候可以使用大小写,但通常情况下全部用大写字母。
  2. // 定义常量MY_FAV并赋值7
  3. const MY_FAV = 7;
  4. // 报错
  5. MY_FAV = 20;
  6. // 输出 7
  7. console.log("my favorite number is: " + MY_FAV);
  8. // 尝试重新声明会报错
  9. const MY_FAV = 20;
  10. // MY_FAV 保留给上面的常量,这个操作会失败
  11. var MY_FAV = 20;
  12. // 也会报错
  13. let MY_FAV = 20;
  14. // 注意块范围的性质很重要
  15. if (MY_FAV === 7) {
  16. // 没问题,并且创建了一个块作用域变量 MY_FAV
  17. // (works equally well with let to declare a block scoped non const variable)
  18. let MY_FAV = 20;
  19. // MY_FAV 现在为 20
  20. console.log('my favorite number is ' + MY_FAV);
  21. // 这被提升到全局上下文并引发错误
  22. var MY_FAV = 20;
  23. }
  24. // MY_FAV 依旧为7
  25. console.log("my favorite number is " + MY_FAV);
  26. // 常量要求一个初始值
  27. const FOO; // SyntaxError: missing = in const declaration
  28. // 常量可以定义成对象
  29. const MY_OBJECT = {"key": "value"};
  30. // 重写对象和上面一样会失败
  31. MY_OBJECT = {"OTHER_KEY": "value"};
  32. // 对象属性并不在保护的范围内,下面这个声明会成功执行
  33. MY_OBJECT.key = "otherValue";
  34. // 也可以用来定义数组
  35. const MY_ARRAY = [];
  36. // It's possible to push items into the array
  37. // 可以向数组填充数据
  38. MY_ARRAY.push('A'); // ["A"]
  39. // 但是,将一个新数组赋给变量会引发错误
  40. MY_ARRAY = ['B']

let

let语句声明一个块级作用域的本地变量,并且可以选择将其初始化为一个值。

  1. let x = 1;
  2. if (x === 1) {
  3. let x = 2;
  4. console.log(x);
  5. // expected output: 2
  6. }
  7. console.log(x);
  8. // expected output: 1

描述

letvar关键字不同的是,var声明的变量只能是全局或者整个函数块的,let在编译的时候才会被初始化。

  1. function varTest() {
  2. var x = 1;
  3. {
  4. var x = 2; // 同样的变量!
  5. console.log(x); // 2
  6. }
  7. console.log(x); // 2
  8. }
  9. function letTest() {
  10. let x = 1;
  11. {
  12. let x = 2; // 不同的变量
  13. console.log(x); // 2
  14. }
  15. console.log(x); // 1
  16. }

在程序和方法的最顶端,let不像 var 一样,let不会在全局对象里新建一个属性。比如:

位于函数或代码顶部的var声明会给全局对象新增属性, 而let不会。例如:

  1. var x = 'global';
  2. let y = 'global';
  3. console.log(this.x); // "global"
  4. console.log(this.y); // undefined

重复声明 (important)

在同一个函数或块作用域中重复声明同一个变量会引起SyntaxError

  1. if(x){
  2. let foo;
  3. let foo; // SyntaxError thrown
  4. }

同样的,在switch语句中只有一个块,可能因此也遇到错误。

  1. let x = 1;
  2. switch(x) {
  3. case 0:
  4. let foo;
  5. break;
  6. case 1:
  7. let foo; // SyntaxError for redeclaration.
  8. break;
  9. }

然而,需要特别指出的是,一个嵌套在 case 子句中的块会创建一个新的块作用域的词法环境,就不会产生上诉重复声明的错误。

  1. let x = 1;
  2. switch(x) {
  3. case 0: {
  4. let foo;
  5. break;
  6. }
  7. case 1: {
  8. let foo;
  9. break;
  10. }
  11. }

暂存死区

与通过 var 声明的有初始化值 undefined 的变量不同,通过 let 声明的变量直到它们的定义被执行时才初始化。在变量初始化前访问该变量会导致 ReferenceError。该变量处在一个自块顶部到初始化处理的“暂存死区”中。

  1. function do_something() {
  2. console.log(bar); // undefined
  3. console.log(foo); // ReferenceError
  4. var bar = 1;
  5. let foo = 2;
  6. }