目录
1.定型数组
定型数组(typed array)是 ECMAScript 新增的结构,目的是提升向原生库传输数据的效率。实际上, JavaScript 并没有“TypedArray”类型,它所指的其实是一种特殊的包含数值类型的数组。
1.来源
在 WebGL 的早期版本中,因为 JavaScript 数组与原生数组之间不匹配,所以出现了性能问题。图形驱动程序 API 通常不需要以 JavaScript 默认双精度浮点格式传递给它们的数值,而这恰恰是 JavaScript数组在内存中的格式。
Mozilla 为解决这个问题而实现了 CanvasFloatArray 。这是一个提供JavaScript接口的、C语言风格的浮点值数组。最终, CanvasFloatArray变成了 Float32Array ,也就是今天定型数组中可用的第一个“类型”。
2.ArrayBuffer
ArrayBuffer() 是一个普通的 JavaScript 构造函数,可用于在内存中分配特定数量的字节空间。
const buf = new ArrayBuffer(16); // 在内存中分配 16 字节
alert(buf.byteLength); // 16
ArrayBuffer 一经创建就不能再调整大小。但可以使用 slice() 复制其全部或部分到一个新实例中:
const buf1 = new ArrayBuffer(16);
const buf2 = buf1.slice(4, 12);
alert(buf2.byteLength); // 8
3.DataView
须在对已有的 ArrayBuffer 读取或写入时才能创建 DataView 实例。这个实例可以使用全部或部分 ArrayBuffer ,且维护着对该缓冲实例的引用,以及视图在缓冲中开始的位置。
const buf = new ArrayBuffer(16);
// DataView 默认使用整个 ArrayBuffer
const fullDataView = new DataView(buf);
alert(fullDataView.byteOffset); // 0
alert(fullDataView.byteLength); // 16
alert(fullDataView.buffer === buf); // true
4.定型数组
定型数组是另一种形式的 ArrayBuffer 视图。虽然概念上与 DataView 接近,但定型数组的区别
在于,它特定于一种 ElementType 且遵循系统原生的字节序。
2.Map
作为 ECMAScript 6 的新增特性, Map 是一种新的集合类型,为这门语言带来了真正的键/值存储机制。 Map 的大多数特性都可以通过 Object 类型实现,但二者之间还是存在一些细微的差异。
1.基本API
// 使用嵌套数组初始化映射
const m1 = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
alert(m1.size); // 3
// 使用自定义迭代器初始化映射
const m2 = new Map({
[Symbol.iterator]: function*() {
yield ["key1", "val1"];
yield ["key2", "val2"];
yield ["key3", "val3"];
}
});
alert(m2.size); // 3
set() 方法再添加键/值对。另外,可以使用 get() 和 has() 进行查询。
与 Object 只能使用数值、字符串或符号作为键不同, Map 可以使用任何 JavaScript 数据类型作为键。
2.迭代和顺序
与 Object 类型的一个主要差异是, Map 实例会维护键值对的插入顺序,因此可以根据插入顺序执
行迭代操作。
可以通过 entries() 方法(或者 Symbol.iterator 属性,它引用 entries() )取得这个迭代器。
3.map和object的选择
1.内存占用
不同浏览器的情况不同,但给定固定大小的内存, Map 大约可以比 Object 多存储 50%的键/值对。
2.插入性能
Map 在所有浏览器中一般会稍微快一点儿如果代码涉及大量插入操作,那么显然 Map 的性能更佳。
3.查找速度
在把 Object 当成数组使用的情况下(比如使用连续整数作为属性),浏览器引擎可以进行优化,在内存中使用更高效的布局。如果代码涉及大量查找操作,那么某些情况下可能选择 Object 更好一些。
4.删除性能
对大多数浏览器引擎来说, Map 的 delete() 操作都比插入和查找更快。如果代码涉及大量删除操作,那么毫无疑问应该选择 Map 。
3.WeakMap
ECMAScript 6 新增的“弱映射”( WeakMap )是一种新的集合类型,为这门语言带来了增强的键/
值对存储机制。 WeakMap 是 Map 的“兄弟”类型,其 API 也是 Map 的子集。 WeakMap 中的“weak”(弱),描述的是 JavaScript 垃圾回收程序对待“弱映射”中键的方式。
1.基本 API
const wm = new WeakMap();
弱映射中的键只能是 Object 或者继承自 Object 的类型,尝试使用非对象设置键会抛出
TypeError 。值的类型没有限制。
初始化之后可以使用 set() 再添加键/值对,可以使用 get() 和 has() 查询,还可以使用 delete()
删除
2.弱键
const wm = new WeakMap();
wm.set({}, "val");
set() 方法初始化了一个新对象并将它用作一个字符串的键。因为没有指向这个对象的其他引用,
所以当这行代码执行完成后,这个对象键就会被当作垃圾回收。然后,这个键/值对就从弱映射中消失了,使其成为一个空映射。
const wm = new WeakMap();
const container = {
key: {}
};
wm.set(container.key, "val");
function removeReference() {
container.key = null;
}
这一次, container 对象维护着一个对弱映射键的引用,因此这个对象键不会成为垃圾回收的目
标。不过,如果调用了 removeReference() ,就会摧毁键对象的最后一个引用,垃圾回收程序就可以把这个键/值对清理掉。
3.不可迭代键
因为 WeakMap 中的键/值对任何时候都可能被销毁,所以没必要提供迭代其键/值对的能力。
4.使用弱映射
1.私有变量
弱映射造就了在 JavaScript 中实现真正私有变量的一种新方式。前提很明确:私有变量会存储在弱映射中,以对象实例为键,以私有成员的字典为值。
外部代码只需要拿到对象实例的引用和弱映射,就可以取得“私有”变量了。为了避免这种访问,可以用一个闭包把 WeakMap 包装起来,这样就可以把弱映射与外界完全隔离开了。
2.DOM 节点元数据
因为 WeakMap 实例不会妨碍垃圾回收,所以非常适合保存关联元数据。
当节点从 DOM 树中被删除后,垃圾回收程序就可以立即释放其内存(假设没有其他地方引用这个对象):
const wm = new WeakMap();
const loginButton = document.querySelector('#login');
// 给这个节点关联一些元数据
wm.set(loginButton, {disabled: true});