今天学习了 es6 中的 let 和 const 命令, 借此整理一下笔记
let :
let 和 var 的声明方式一样, 但有 var 比不上的优点下面用 var 和 let 的例子来加深对 let 的理解
1 let 只作用与当前作用域中
在声明 var 时, 在无特别情况下, 代码块里的 var 外部也可以访问到的, 但是 let 声明之后, 外部是访问不到的, 会报错
- {
- var a = 123
- let b = 456
- }
- console.log(a) // 123
- console.log(b) // ReferenceError: b is not defined
以前面试经常出现的一道题, 下面会打印出什么
- var a = [];
- for (var i = 0; i < 10; i++) {
- a[i] = function () {
- console.log(i);
- };
- }
- a[5]();
结果是 10 , 这就是 var i 没有指定块级作用域, 指向了全局变量 i 是 var 命令声明的, 在全局范围内都有效, 所以全局只有一个变量 i 每一次循环, 变量 i 的值都会发生改变, 而循环内被赋给数组 a 的函数内部的 console.log(i), 里面的 i 指向的就是全局的 i, 数组 a 的成员里面的 i, 指向的都是同一个 i, 导致运行时输出的是最后一轮的 i 的值, 也就是 10
如果使用 let, 利用它的具有块级作用域的特性, 我们可以获取数组 a[5]的值
- var a = [];
- for (let i = 0; i < 10; i++) {
- a[i] = function () {
- console.log(i);
- };
- }
- a[5](); // 5
为何是 5, 而不是 10 了, 因为变量 i 是 let 声明的, 当前的 i 只在本轮循环有效, 所以每一次循环的 i 其实都是一个新的变量, 所以最后输出的是 5
另外 let 为 javascript 添加了块级作用域, 使声明的变量只作用与当前的代码块
- function fn() {
- let n = 1;
- if (true) {
- let n = 2;
- console.log(n) // 2
- }
- console.log(n) // 1
- }
- fn()
而 var 则不会, 因为根据 var 变量声明的原则, if 代码块的 n 重复使用, 后面的覆盖前面的
- function fn() {
- var n = 1;
- if (true) {
- var n = 2;
- console.log(n) // 2
- }
- console.log(n); // 2
- }
- fn()
2 let 不存在变量提升
var 命令会发生变量提升现象, 即变量可以在声明之前使用, 值为 undefined 这是 javascript 在预编译过程中, 把 var 声明的变量提升到当前作用域的最上端, 变量的值不变但是 let 不存在变量提升, 如果未声明就使用或者声明在使用之后会报错 ReferenceError
- console.log(a)
- var a = 1 // undefined
- console.log(b)
- let b = 2 // Uncaught ReferenceError: b is not defined
3 let 具有暂时性死区
只要块级作用域内存在 let 命令, 它所声明的变量就绑定 (binding) 这个区域, 不再受外部的影响
暂时性死区的本质就是, 只要一进入当前作用域, 所要使用的变量就已经存在了, 但是不可获取, 只有等到声明变量的那一行代码出现, 才可以获取和使用该变量
- {
- a = 123
- b = 456
- let a
- var b
- console.log(a) // Uncaught ReferenceError: a is not defined
- console.log(b) // 456
- }
上面的例子的情况就是说明了 let 的暂时性死区, let a 在使用之后, 触发了暂时性死区, 就报错而 var 因为在声明时发生变量提升提到最顶端, 所以能打印出 456
4 let 不允许重复变量
let 不允许在相同作用域内, 重复声明同一个变量, 否则会报错
- {
- let a = 1
- let a = 2 // Uncaught SyntaxError: Identifier 'a' has already been declared
- }
- {
- var a = 1 // Uncaught SyntaxError: Identifier 'a' has already been declared
- let a = 2
- }
5 let 使变量不再是默认的全局变量
- var a = 1
- console.log(window.a) // 1
- let b = 2
- console.log(window.b) // undefined
ES6 规定: 为了保持兼容性, 又不利于模块化变成, 所以 var 命令和 function 命令声明的全局变量, 依旧是顶层对象的属性; let 命令 const 命令 class 命令声明的全局变量, 不属于顶层对象的属性
const:
const 声明一个只读的常量一旦声明, 常量的值就不能改变
- const a = 1
- a = 2 // Uncaught TypeError: Assignment to constant variable.
- console.log(a)
其本质就是: const 一旦声明变量, 就必须立即初始化, 不能留到以后赋值
const 的特点和 let 的一样:
1 只作用与当前的块级作用域
2 不存在变量提升
3 也存在暂时性死区
4 不允许重复声明同一个变量
5 使变量不再是全局属性
ps:const 的本质: 不是变量的值不得改动, 而是变量指向的那个内存地址不得改动
简单类型的数据(数值字符串布尔值), 值就保存在变量指向的那个内存地址, 因此等同于常量
复合类型的数据(主要是对象和数组), 变量指向的内存地址, 保存的只是一个指针, 里面的内容可以改变
- const a = 'string'
- a = 'String' // Uncaught TypeError: Assignment to constant variable.
- console.log(a)
- const b = {
- name: 'peter'
- }
- b.name = 'Bob'
- console.log(b) // {name: "Bob"}
- b = {} //error
- console.log(b)
a 是字符串, 值就保存在地址, 不可变, 一变就报错
b 是个对象, 对象保存的是个地址, 是个指针, 只要地址不变, 里面的内容可以捣鼓, 但是如果要把这个对象 b 初始化等等就相当于改变了地址
参考资料:
阮一峰大大的 es6: http://es6.ruanyifeng.com
来源: https://www.cnblogs.com/sqh17/p/8533744.html