let 命令
基本用法
它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
for循环的计数器,就很合适使用let命令。
for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
不存在变量提升
var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined。
let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
暂时性死区(temporal dead zone,简称 TDZ)。
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。
不允许重复声明
let不允许在相同作用域内,重复声明同一个变量。
因此,不能在函数内部重新声明参数。
function func(arg) {
let arg; // 报错
}
function func(arg) {
{
let arg; // 不报错
}
}
块级作用域
为什么需要块级作用域?
- 内层变量可能会覆盖外层变量。
- 用来计数的循环变量泄露为全局变量。
ES6的块级作用域
- let实际上为 JavaScript 新增了块级作用域。
- ES6 允许块级作用域的任意嵌套。
- 外层作用域无法读取内层作用域的变量。
- 内层作用域可以定义外层作用域的同名变量。
块级作用域与函数声明
- 考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。
// 函数声明语句
{
let a = 'secret';
function f() {
return a;
}
}
// 函数表达式
{
let a = 'secret';
let f = function () {
return a;
};
}
- ES6 的块级作用域允许声明函数的规则,只在使用大括号的情况下成立,如果没有使用大括号,就会报错。
// 不报错
'use strict';
if (true) {
function f() {}
}
// 报错
'use strict';
if (true)
function f() {}
do 表达式
- 在块级作用域之前加上do,使它变为do表达式,然后就会返回内部最后执行的表达式的值。
const 命令
基本用法
- const声明一个只读的常量。一旦声明,常量的值就不能改变。
- const一旦声明变量,就必须立即初始化,不能留到以后赋值。只声明不赋值,就会报错。
- 只在声明所在的块级作用域内有效。
- 声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
- 不可重复声明。
本质
- const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。
- e.g.1: 常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。
const foo = {};
// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123
// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only
- e.g. 2:常量a是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a,就会报错。
const a = [];
a.push('Hello'); // 可执行
a.length = 0; // 可执行
a = ['Dave']; // 报错
小结:ES6 声明变量的六种方法
ES6 除了添加let和const命令,import命令和class命令。所以,ES6 一共有 6 种声明变量的方法。
顶层对象的属性
- var命令和function命令声明的全局变量,依旧是顶层对象的属性;
- let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。
- 也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1,全局变量a由var命令声明,所以它是顶层对象的属性;
let b = 1;
window.b //全局变量b由let命令声明,所以它不是顶层对象的属性,返回undefined。
global 对象
- 垫片库
system.global
模拟了这个提案,可以在所有环境拿到global
。
// CommonJS 的写法
require('system.global/shim')();
// ES6 模块的写法
import shim from 'system.global/shim'; shim();
- 将顶层对象放入变量global。
// CommonJS 的写法
var global = require('system.global')();
// ES6 模块的写法
import getGlobal from 'system.global';
const global = getGlobal();