let关键字特性

(1)不存在变量提升=>存在暂时性死区

暂时性死区会出现在使用 let 或 const 的代码中,使用 let 或 const 声明的变量会先在作用域中被创建出来,但此时还未进行赋值,如果此时对该变量进行求值运算,变量是不能被访问的,访问就会抛出异常。
因为有暂时性死区的存在,typeof 运算符也不再是绝对安全的,在 let 定义的变量之前使用 typeof 运算符同样会抛出异常。

  1. if (true) {
  2. // 暂时性死区开始
  3. param = 'kingx';
  4. console.log(param); // ReferenceError: Cannot access 'param' before initialization
  5. typeof param; // ReferenceError: Cannot access 'param' before initialization
  6. // ……
  7. // 暂时性死区结束
  8. let param;
  9. }

(2)不能重复声明

在同一个作用域内,不能使用let重复声明相同的变量。

  1. function foo() {
  2. let arg1 = 'kingx';
  3. if (true) {
  4. let arg1 = 'kingx'; // 不影响
  5. }
  6. var arg1 = 'kingx'; // SyntaxError: Identifier 'arg1' has already been declared
  7. }
  8. function foo(arg1) {
  9. let arg1 = 'kingx'; // SyntaxError: Identifier 'arg1' has already been declared
  10. }

(3)不再是全局对象的属性

在ES6以前,在浏览器环境的全局作用域下,使用var声明的变量、函数表达式或者函数声明均是window对象的属性。
在ES6以后,依然遵循上述原则,但是如果是使用 let 声明的变量或者函数表达式,将不再是 window对象的属性。

  1. // var声明的变量和函数表达式
  2. var a = 1;
  3. var fn = function () {
  4. console.log('global method');
  5. };
  6. console.log(window.a); // 1
  7. window.fn(); // global method
  8. // let声明的变量和函数表达式
  9. let b = 2;
  10. let foo = function () {
  11. console.log('global method');
  12. };
  13. console.log(window.b); // undefined
  14. window.foo(); // TypeError: window.foo is not a function

let关键字好处

(1)不会导致for循环索引值泄露

在 for 循环中,因为循环的索引值一般只会在循环体内有效,所以当循环结束后索引值应该被回收。但是如果通过 var 定义索引值的话,该索引值在循环结束后仍然可以访问,此时使用let定义循环的索引值就很合适。

(2)避免出现变量提升导致的变量覆盖问题

ES6之前只有全局作用域和函数作用域,在函数作用域中通过 var 声明的变量会提升到函数作用域顶端,覆盖函数作用域里引用的全局变量(变量声明不受if(false)影响

  1. var arg1 = 'kingx';
  2. function foo() {
  3. console.log(arg1); // undefined
  4. if (false) { // 变量声明不受if(false)影响
  5. var arg1 = 'kingx2';
  6. }
  7. }
  8. foo(); // undefined

(3)代替立即执行函数IIFE

立即执行函数(Immediately-Invoked Function Expression)的内部是一个独立的函数级作用域,使用IIFE的目的主要是避免污染当前作用域内的变量,而使用块级作用域则可以直接避免这个问题。

  1. // IIFE 块级作用域写法
  2. (function () {
  3. let arg = ...;
  4. ...
  5. }());

const关键字特性

(1)声明的值为一个常量,一旦声明将不会再改变。

对于基本类型的变量来说,变量就保存着内存地址的值,因此不能直接修改;而对于引用类型的变量来说,变量保存的是一个指向数据内存地址的指针,只要该指针固定不变,我们就可以改变数据本身的值。

(2)在声明时就必须初始化

使用const声明常量时,在声明时就必须初始化。如果只声明,不初始化,则会抛出异常。

  1. const MAX = 16;
  2. const MIN; // SyntaxError: Missing initializer in const declaration

(3)其它特性跟 let 一样