let & const

let 命令

基本用法
  1. 它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

  2. for循环的计数器,就很合适使用let命令。

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

不存在变量提升
  1. var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined

  2. let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

暂时性死区(temporal dead zone,简称 TDZ)。
  1. 在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

  2. 只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

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

  2. 因此,不能在函数内部重新声明参数。

function func(arg) {
  let arg; // 报错
}

function func(arg) {
  {
    let arg; // 不报错
  }
}

块级作用域

为什么需要块级作用域?
  1. 内层变量可能会覆盖外层变量。
  2. 用来计数的循环变量泄露为全局变量。
ES6的块级作用域
  1. let实际上为 JavaScript 新增了块级作用域。
  2. ES6 允许块级作用域的任意嵌套。
  3. 外层作用域无法读取内层作用域的变量。
  4. 内层作用域可以定义外层作用域的同名变量。
块级作用域与函数声明
  1. 考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。
// 函数声明语句
{
  let a = 'secret';
  function f() {
    return a;
  }
}

// 函数表达式
{
  let a = 'secret';
  let f = function () {
    return a;
  };
}
  1. ES6 的块级作用域允许声明函数的规则,只在使用大括号的情况下成立,如果没有使用大括号,就会报错。
// 不报错
'use strict';
if (true) {
  function f() {}
}

// 报错
'use strict';
if (true)
  function f() {}
do 表达式
  1. 在块级作用域之前加上do,使它变为do表达式,然后就会返回内部最后执行的表达式的值。

const 命令

基本用法
  1. const声明一个只读的常量。一旦声明,常量的值就不能改变。
  2. const一旦声明变量,就必须立即初始化,不能留到以后赋值。只声明不赋值,就会报错。
  3. 只在声明所在的块级作用域内有效。
  4. 声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
  5. 不可重复声明。
本质
  1. const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。
  2. e.g.1: 常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。
const foo = {};

// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123

// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only
  1. e.g. 2:常量a是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a,就会报错。
const a = [];
a.push('Hello'); // 可执行
a.length = 0;    // 可执行
a = ['Dave'];    // 报错

小结:ES6 声明变量的六种方法

ES6 除了添加let和const命令,import命令和class命令。所以,ES6 一共有 6 种声明变量的方法。


顶层对象的属性

  1. var命令和function命令声明的全局变量,依旧是顶层对象的属性;
  2. let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。
  3. 也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩
var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1,全局变量a由var命令声明,所以它是顶层对象的属性;

let b = 1;
window.b //全局变量b由let命令声明,所以它不是顶层对象的属性,返回undefined。


global 对象

  1. 垫片库system.global模拟了这个提案,可以在所有环境拿到global
// CommonJS 的写法
require('system.global/shim')();

// ES6 模块的写法
import shim from 'system.global/shim'; shim();
  1. 将顶层对象放入变量global。
// CommonJS 的写法
var global = require('system.global')();

// ES6 模块的写法
import getGlobal from 'system.global';
const global = getGlobal();

你可能感兴趣的:(let & const)