ES6|ES6中 let 和 const 命令熟悉
文章目录
- ES6
- 1.0 let 和 const 命令
- 1.0 let 命令
- 2.0 块级作用域
- 3.0 ES6 的块级作用域
- 4.0 const 命令
- 5.0 顶层对象的属性
- 总结:
ES6 1.0 let 和 const 命令 1.0 let 命令
ES6新增了let
命令, 但是它与var
不同的是,let
所声明的变量, 只在let
命令所在的代码块内有效.
{ let a = '我是let声明变量'; var b = '我是var声明变量' } // console.log(a); // ReferenceError: a is not defined console.log(b);
let
声明的变量不存在变量提升
存在暂时性死区2.0 块级作用域
只要块级作用域内 存在let
命令, 它所声明的变量就"绑定(binding)" 这个区域, 不再受外部影响
var temp = 123 if (true) { temp = 'abc'; // ReferenceError: temp is not defined let temp console.log(temp); }
上面这段代码中, 存在全局变量ES6明确规定, 如果区块中 存在temp
, 但是块级作用域内let
又声明了一个局部变量temp
, 导致块级作用域内的局部变量temp
绑定这个块级作用域, 全局变量temp
对块级作用域无效, 所以在let
声明变量之前, 对temp
赋值会报错.
let
和const
命令 这个区块对用let
和const
声明的变量, 从一开始就形成了封闭作用域. 凡是在声明变量之前就使用这些变量, 就会报错.
总之, 在代码块内, 使用let
命令声明变量之前, 该变量都是不可用的. 这在语法上, 成为 “暂时性死区” (temporal dead zone, 简称 TDZ)
if (true) { // TDZ开始 tmp = 'abc'; // ReferenceError console.log(tmp); // ReferenceErrorlet tmp; // TDZ结束 console.log(tmp); // undefinedtmp = 123; console.log(tmp); // 123 }
上述代码中, 在let
命令声明变量tmp
之前, 都属于tmp
的 “死区”
为什么需要块级作用域?3.0 ES6 的块级作用域
ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景
- 场景一: 内层变量可能会覆盖外层变量
var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = 'hello world'; } }f(); // undefined
上面代码的原意是,if
代码块的外部使用外层的tmp
变量,内部使用内层的tmp
变量。但是,函数f
执行后,输出结果为undefined
,原因在于变量提升,导致内层的tmp
变量覆盖了外层的tmp
变量。
- 场景二: 用来计数的循环变量泄露为全局变量
var s = 'hello'; for (var i = 0; i < s.length; i++) { console.log(s[i]); } console.log(i); // 5
上面代码中, 变量i
只是用来控制循环, 但循环结束后, 它并没有消失, 泄露成了全局变量. 这种方式不安全.
4.0 const 命令let
实际上为 JavaScript新增了块级作用域
function f1() { let n = 5; if (true) { let n = 10; // 块级作用域内, 不影响外部的同名变量 n } console.log(n); // 5 } f1()
const
声明一个只读的常量, 一旦声明, 常量的值不能改变.
const
声明的变量不得改变值,这意味着,const
一旦声明变量,就必须立即初始化,不能留到以后赋值。
const foo; // SyntaxError: Missing initializer in const declaration
const
的作用域与let
命令相同:只在声明所在的块级作用域内有效const
命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
本质:
const
实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。
但是: 对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const
只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
const foo ={} foo.name = 'Gene' // 为foo对象添加一个属性, 可以添加成功 console.log(foo); // { name: 'Gene' } foo = {} // 将foo指向另一个值或对象就会报错
上面代码中,常量foo
储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo
指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。
再看如下的例子5.0 顶层对象的属性
const a = []; a.push('Hello'); // 可执行 a.length = 0; // 可执行 a = ['Dave']; // 报错
上面代码中,常量a
是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a
,就会报错。
顶层对象,在浏览器环境指的是总结:window
对象,在 Node 指的是global
对象。ES5 之中,顶层对象的属性与全局变量是等价的。
window.a = 1; a // 1a = 2; window.a // 2
上面代码中,顶层对象的属性赋值与全局变量的赋值,是同一件事。
该博客为学习阮一峰 ES6入门课时所做的笔记记录, 仅供留作笔记记录学习和理解.
交流学习加 WeChat(备注技术交流学习):
文章图片
【ES6|ES6中 let 和 const 命令熟悉】下一章: ES6变量的解构赋值详解
推荐阅读
- 热闹中的孤独
- Shell-Bash变量与运算符
- JS中的各种宽高度定义及其应用
- 2021-02-17|2021-02-17 小儿按摩膻中穴-舒缓咳嗽
- 深入理解Go之generate
- 异地恋中,逐渐适应一个人到底意味着什么()
- 我眼中的佛系经纪人
- 《魔法科高中的劣等生》第26卷(Invasion篇)发售
- “成长”读书社群招募
- 2020-04-07vue中Axios的封装和API接口的管理