学习笔记 2020-10-13
JavaScript 高级程序设计(第4版) 阅读记录
集合引用类型
Map
set
方法返回映射实例,因此可以链式调用。
const m = new Map().set("key1", "val1");
m.set("key2", "val2")
.set("key3", "val3");
console.log(m.size); // 3
Map
可以使用任何数据类型作为键,使用严格相等来匹配。
const m = new Map();
const functionKey = function() {};
const symbolKey = Symbol();
const objectKey = new Object();
m.set(functionKey, "functionValue");
m.set(symbolKey, "symbolValue");
m.set(objectKey, "objectValue");
console.log(m.get(functionKey)); // functionValue
console.log(m.get(symbolKey)); // symbolValue
console.log(m.get(objectKey)); // objectValue
// SameValueZero 比较意味着独立实例不冲突
console.log(m.get(function() {})); // undefined
Map
保持插入顺序不变。
const m = new Map([
['key1', 'val1'],
['key2', 'val2'],
['key3', 'val3']
]);
console.log(m.entries === m[Symbol.iterator]); // true
for (let pair of m.entries()) {
console.log(pair);
}
// [key1,val1]
// [key2,val2]
// [key3,val3]
for (let pair of m[Symbol.iterator]()) {
console.log(pair);
}
// [key1,val1]
// [key2,val2]
// [key3,val3]
const m = new Map([
['key1', 'val1'],
['key2', 'val2'],
['key3', 'val3']
]);
console.log([...m]); // [[key1,val1],[key2,val2],[key3,val3]]
Map
的 keys()
values()
方法分别返回插入顺序生成的键和值的迭代器。
选择 Object 还是 Map
在内存占用方面,两种类型都会随键的数量线性增加。但给定固定大小的内存, Map
可以多存储 50%
的键值对。
在插入性能方面,消耗相当。但插入 Map
会稍快。
在查找速度方面,性能差异极小,涉及大量查找时,Object
会更好。
在删除性能方面,Map
表现更好。
WeakMap
ES6
新增的集合类型,弱映射。其 Api
是 Map
的子集。
弱映射的键只能是 Object
或是继承自 Object
的类型。值的类型没有限制。
可以将原始值包装成对象用作键。
WeakMap
的键不属于正式引用,不会阻止垃圾回收。当键没有其余指向它的引用时,在代码执行完成后,就会被垃圾回收,键值对就会从弱映射中消失。
WeakMap
没有迭代方法,没有一次性销毁所有键值的方法。
弱映射的用处:
私有变量
const wm = new WeakMap(); class User { constructor(id) { this.idProperty = Symbol('id'); this.setId(id); } setPrivate(property, value) { const privateMembers = wm.get(this) || {}; privateMembers[property] = value; wm.set(this, privateMembers); } getPrivate(property) { return wm.get(this)[property]; } setId(id) { this.setPrivate(this.idProperty, id); } getId() { return this.getPrivate(this.idProperty); } } const user = new User(123); console.log(user.getId()); // 123 user.setId(456); console.log(user.getId()); // 456 // 并不是真正私有的 console.log(wm.get(user)[user.idProperty]); // 456
为了防止外部获取到弱映射而破坏了私有性。我们可以使用闭包:
const User = (() => { const wm = new WeakMap(); class User { constructor(id) { this.idProperty = Symbol('id'); this.setId(id); } setPrivate(property, value) { const privateMembers = wm.get(this) || {}; privateMembers[property] = value; wm.set(this, privateMembers); } getPrivate(property) { return wm.get(this)[property]; } setId(id) { this.setPrivate(this.idProperty, id); } getId(id) { return this.getPrivate(this.idProperty); } } return User; })(); const user = new User(123); console.log(user.getId()); // 123 user.setId(456); console.log(user.getId()); // 456
DOM
节点元数据如果使用常规的
Map
来保存DOM
节点,当DOM
节点在DOM
树中被销毁,我们依然保存着它的引用,DOM
节点依然保存在内存中。若是采用弱映射,就不会发生这种状况。
Set
ES6
新增的集合类型。
const m = new Set();
const s1 = new Set(["val1", "val2", "val3"]);
console.log(s1.size); // 3
const s2 = new Set({
[Symbol.iterator]: function*() {
yield "val1";
yield "val2";
yield "val3";
}
});
console.log(s2.size); // 3
基本 API
:
add()
has()
size
delete()
返回集合中是否存在要删除的值。
clear()
add
方法同样返回集合实例,可以链式调用。使用严格相等来进行匹配。
现代 JavaScript 教程
函数表达式与函数声明的区别
- 函数声明是一段代码块,函数表达式是一个赋值语句。
- 函数表达式仅在代码执行到达时才会创建该函数,且从此刻开始可用。函数声明会在脚本开始运行时被创建,在声明语句之前也可以调用该函数。
TODO-LIST
- 想尝试一下
hugo
作为博客。 - 整理 18 年的笔记。