0%

学习笔记 2020 10 13

学习笔记 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]]

Mapkeys() values() 方法分别返回插入顺序生成的键和值的迭代器。

选择 Object 还是 Map

在内存占用方面,两种类型都会随键的数量线性增加。但给定固定大小的内存, Map 可以多存储 50% 的键值对。

在插入性能方面,消耗相当。但插入 Map 会稍快。

在查找速度方面,性能差异极小,涉及大量查找时,Object 会更好。

在删除性能方面,Map 表现更好。

WeakMap

ES6 新增的集合类型,弱映射。其 ApiMap 的子集。

弱映射的键只能是 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 教程

函数表达式与函数声明的区别

  1. 函数声明是一段代码块,函数表达式是一个赋值语句。
  2. 函数表达式仅在代码执行到达时才会创建该函数,且从此刻开始可用。函数声明会在脚本开始运行时被创建,在声明语句之前也可以调用该函数。

TODO-LIST

  • 想尝试一下 hugo 作为博客。
  • 整理 18 年的笔记。