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 声明的变量不存在变量提升
存在暂时性死区
只要块级作用域内 存在 let命令, 它所声明的变量就"绑定(binding)" 这个区域, 不再受外部影响
var temp = 123 if (true) { temp = 'abc'; // ReferenceError: temp is not defined let temp console.log(temp); }

上面这段代码中, 存在全局变量temp, 但是块级作用域内 let 又声明了一个局部变量 temp , 导致块级作用域内的局部变量temp绑定这个块级作用域, 全局变量temp对块级作用域无效, 所以在 let 声明变量之前, 对 temp赋值会报错.
ES6明确规定, 如果区块中 存在 letconst 命令 这个区块对用 letconst 声明的变量, 从一开始就形成了封闭作用域. 凡是在声明变量之前就使用这些变量, 就会报错.
总之, 在代码块内, 使用 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 的 “死区”
2.0 块级作用域
为什么需要块级作用域?
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 只是用来控制循环, 但循环结束后, 它并没有消失, 泄露成了全局变量. 这种方式不安全.
3.0 ES6 的块级作用域
let 实际上为 JavaScript新增了块级作用域
function f1() { let n = 5; if (true) { let n = 10; // 块级作用域内, 不影响外部的同名变量 n } console.log(n); // 5 } f1()

4.0 const 命令
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指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。
再看如下的例子
const a = []; a.push('Hello'); // 可执行 a.length = 0; // 可执行 a = ['Dave']; // 报错

上面代码中,常量a是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a,就会报错。
5.0 顶层对象的属性
顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。ES5 之中,顶层对象的属性与全局变量是等价的。
window.a = 1; a // 1a = 2; window.a // 2

上面代码中,顶层对象的属性赋值与全局变量的赋值,是同一件事。
总结:
该博客为学习阮一峰 ES6入门课时所做的笔记记录, 仅供留作笔记记录学习和理解.
交流学习加 WeChat(备注技术交流学习):
ES6|ES6中 let 和 const 命令熟悉
文章图片

【ES6|ES6中 let 和 const 命令熟悉】下一章: ES6变量的解构赋值详解

    推荐阅读