JavaScript之常量

简单类型常量

众所周知 ES6 新增的 const 关键字可以用来声明常量。常量是块级作用域,很像使用 let 语句定义的变量。常量的值不能通过重新赋值来改变,并且不能重新声明。

1
2
const name = 'zubin';
name = 'zhang'; //TypeError: Assignment to constant variable.

const 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动,对于基本数据类型(Number、String、Boolean 等),值就保存在变量指向的内存地址,因此等同于常量。
对于复合类型(Object、Array 等)变量指向的内存地址,保存的只是一个指向实际数据的指针,const 只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。

1
2
3
4
5
6
7
8
9
10
11
12
13
const foo = {};

// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop; // 123

// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError

const a = [];
a.push('Hello'); // 可执行
a.length = 0; // 可执行
a = ['Dave']; // TypeError

复合类型常量

如果真的想将对象冻结,应该使用 Object.freeze 方法,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。该方法返回被冻结的对象。

1
2
3
4
5
const foo = Object.freeze({});

// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
foo.prop = 123;

除了将对象本身冻结,对象的属性也应该冻结。

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]);
}
});
};

参考文档

阮一峰:ECMAScript 6 入门
MDN:Object.freeze

ES6中Map和Object的区别

JavaScript 的对象(Object)和 Map,本质上是键值对的集合(Hash 结构)

ES6 中 Map 相对于 Object 对象有几个区别:

  • 对象(Object)和只能用字符串和 Symbol 当作键,Map 的 key 可以是任何基本类型或者对象
  • Map 可以通过 size 获取到长度,Object 获取长度的比较复杂
  • Map 具有 Symbol.iterator 属性,可通过 for…of 循环遍历

Map 转为对象:

  • 如果所有 Map 的键都是字符串或者 Symbol,它可以无损地转为对象。
  • 如果有非字符串的键名,那么这个键名会被转成字符串,再作为对象的键名。
阅读更多

JavaScript装饰器

随着 ES6 里引入了类,目前 ECMAScript 有一个提案,引入了装饰器(Decorator)函数来标注极或修改类及其成员。
装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上。 装饰器使用 @expression 这种形式,expression 求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。

关于装饰器的详细介绍请参阮一峰的《ECMAScript 6 入门》一书

阅读更多