ES6学习 —— const命令

本文是学习 阮一峰《ECMAScript 6 入门》 const 命令 部分的笔记。

基本用法

  • const 声明一个只读的常量,一旦声明,常量的值就不能改变;
  • const 一旦声明变量,就必须立即初始化,不能留到以后赋值;
  • const 的作用域:只在声明所在的块级作用域内有效;
  • const 声明的常量不提升,同样也存在暂时性死区,必须先声明再使用;
  • const 声明的常量,不能重复声明;
    (后面三条用法与 let 命令一致)

下面来看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const M = 10;
M = 2; // Uncaught TypeError: Assignment to constant variable.
const P; // Uncaught SyntaxError: Missing initializer in const declaration
if(true){
const Q = 20;
}
console.log(Q); // Uncaught ReferenceError: Q is not defined
if(true){
console.log(K); // Uncaught ReferenceError: K is not defined
const K = 30;
}
var name = "Bob";
let age = 25;
const name = "Alice"; // Uncaught SyntaxError: Identifier 'name' has already been declared
const age = 18; // Uncaught SyntaxError: Identifier 'age' has already been declared

const 命令的本质

const 实际上保证的,并不是变量的值不能改变,而是变量指向的那个内存地址不能改变。

对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于变量的值不能改变;

而对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const 命令只能保证这个指针是固定的,而不能保证指针指向的数据结构也是不变的。

下面分别是这两种类型数据的存储形式:
基本类型数据
引用类型数据
(图片来源于网络)

因此,将对象或者数组声明为常量必须非常小心!

下面就对象和数组分别举例进行说明:

对象

1
2
3
4
5
6
const person = {}; // 将 person 对象声明为一个常量
person.name = "Bob"; // 为 person 添加一个属性
console.log(person.name); // Bob
person = {}; // Uncaught TypeError: Assignment to constant variable.

上面代码中,常量 person 存储的是一个地址,这个地址指向一个对象。而根据前面的分析,不可改变的是这个地址,也就是说不能把 person 指向另一个地址, 但对象本身是可以改变的。因此,给 person 添加新的属性不会报错。

但是如果将 person 指向另一个地址(对象),就会报错。

那有没有办法可以让对象本身也不能改变呢?

可以使用 Object.freeze 方法将对象冻结,从而无法改变对象本身。

1
2
3
4
5
const person = Object.freeze({});
person.name = "Alice";
// 常规模式下,上面一行不起作用
// 严格模式下, 会报错!

除了将对象本身冻结之外,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数:(没太看懂)

1
2
3
4
5
6
7
8
var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach((key,i) => {
if(typeof obj[key] === 'object'){ // 如果对象的属性不是“对象”,就不冻结吗?
constantize(obj[key]);
}
});
};

数组

1
2
3
4
5
const a = [];
a.push('hello');
a.length = 10;
a = ['world']; // Uncaught TypeError: Assignment to constant variable.

常量 a 是一个数组,而数组本身是可以改变的,但是如果将一个新的数组赋值给 a ,就会报错。因此上面代码中,设置数组 a 的属性以及给数组a 添加元素,都是可执行的,而最后将新数组 ["world"] 赋值给数组 a ,就报错了。

您的支持将鼓励我继续创作!