ES6-let & const命令
let命令
基本用法
ES6新增了let
命令,用法类似于var
,但是所声明的变量只在let所在的代码块生效
1 | { |
for循环中的let
1 | for (let i = 0; i < 3; i++) { |
上述代码中的i
由let
声明,只在for
循环体内有效,在循环体外引用则会报错
1 | for (var i = 0; i < 3; i++) { |
上述代码中的i
由var
声明,在全局范围内有效,全局只有一个变量i
1 | var a = []; |
当循环中的i
由let
声明时,当前一轮循环中的i
只在本轮循环中有效。每一次循环中的i
其实是一个新的变量,JavaScript
引擎内部会记住上一轮循环的值,初始化本轮i
的值是在上一轮的基础上计算。
for
循环设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域
1 | for (let i = 0; i < 3; i++) { |
不存在变量提升
let
所声明的变量一定要在声明后使用,否则会报错
1 | console.log(i); |
暂时性死区(temporal dead zone, TDZ)
ES6规定:如果区块中存在let
或const
命令,则这个区块对这些命令声明的变量从一开始就形成封闭作用域,只要在声明之前就使用这些变量,就会报错
1 | { |
变量一定要在声明之后使用
1 | var a = 1; |
一些隐蔽的死区:
x的默认值等于y,而y还没有声明
1
2
3
4(function f(x = y, y = 2) {
return [x, y];
})();
// Uncaught ReferenceError: y is not defined在
x
的声明语句还没执行完之前就尝试获取x
的值1
2
3let x = x; // => Uncaught ReferenceError: y is not defined
------------------------------------------------
var x = x; // 不报错
不允许重复声明
let
不允许在相同作用域内重复声明同一个变量
1 | function f() { |
不能在函数内部重新声明参数
1 | function f(a) { |
const命令
基本用法
const
命令声明一个只读的常量。一旦声明,常量的值就不能改变
1 | const PI = 3.1415; |
const
一旦声明常量,必须立即初始化,不能留到以后赋值
1 | const a; // => Uncaught SyntaxError: Missing initializer in const declaration |
const
只在声明所在的块级作用域内有效
1 | if (true) { |
const
命令不存在变量提升,存在TDZ,只能在声明后使用
1 | if (true) { |
const
不可重复声明
1 | var a = 1; |
本质
const
实际上保证的不是变量的值不得改动,而是变量指向的那个内存地址不得改动
对简单类型的数据,值保存在变量指向的内存地址中,因此等同于常量
对复合类型的数据,变量指向的内存地址保存的只是一个指针,它指向的数据结构是不是可变则完全不可控
1 | const obj = {}; |
想将对象冻结,可以使用Object.freeze()
方法
1 |
|
块级作用域
ES6的块级作用域
let
和const
实际上为JavaScript增加了块级作用域
1 | (function () { |
ES6允许块级作用域的任意嵌套。外层作用域无法读取内存作用域的变量,内层作用域可以定义外层作用域的同名变量
1 | { |
块级作用域与函数声明
为减轻不兼容问题,ES6规定:
- 允许在块级作用域内声明函数
- 函数声明类似于
var
,即会提升到全局作用域或函数作用域的头部 - 同时,函数声明还会提升到所在的块级作用域的头部
1 | function f() { |