每个人都想有所成就,却不知信手拈来的从容都是厚积薄发的沉淀。
今日学习内容 1、JS 红皮书 P176-179 第六章:集合引用类型
今日笔记 1、从各方面来看,Set 跟 Map 都很相似,只是 API 稍有调整。唯一需要强调的就是集合的 API 对自身的简单操作。很多开发者都喜欢使用 Set 操作,但需要手动实现:或者是子类化 Set,或者是定义一个实用函数库。要把两种方式合二为一,可以在子类上实现静态方法,然后在实例方法中使用这些静态方法。在实现这些操作时,需要考虑几个地方。 某些 Set 操作是有关联性的,因此最好让实现的方法能支持处理任意多个集合实例。 Set 保留插入顺序,所有方法返回的集合必须保证顺序。 尽可能高效地使用内存。扩展操作符的语法很简洁,但尽可能避免集合和数组间的相互转换能够节省对象初始化成本。 不要修改已有的集合实例。union(a, b)或 a.union(b)应该返回包含结果的新集合实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 class XSet extends Set { union (...sets ) { return XSet .union (this , ...sets); } intersection (...sets ) { return XSet .intersection (this , ...sets); } difference (set ) { return XSet .difference (this , set); } symmetricDifference (set ) { return XSet .symmetricDifference (this , set); } cartesianProduct (set ) { return XSet .cartesianProduct (this , set); } powerSet ( ) { return XSet .powerSet (this ); } static union (a, ...bSets ) { const unionSet = new XSet (a); for (const b of bSets) { for (const bValue of b) { unionSet.add (bValue); } } return unionSet; } static intersection (a, ...bSets ) { const intersectionSet = new XSet (a); for (const aValue of intersectionSet) { for (const b of bSets) { if (!b.has (aValue)) { intersectionSet.delete (aValue); } } } return intersectionSet; } static difference (a, b ) { const differenceSet = new XSet (a); for (const bValue of b) { if (a.has (bValue)) { differenceSet.delete (bValue); } } return differenceSet; } static symmetricDifference (a, b ) { return a.union (b).difference (a.intersection (b)); } static cartesianProduct (a, b ) { const cartesianProductSet = new XSet (); for (const aValue of a) { for (const bValue of b) { cartesianProductSet.add ([aValue, bValue]); } } return cartesianProductSet; } static powerSet (a ) { const powerSet = new XSet ().add (new XSet ()); for (const aValue of a) { for (const set of new XSet (powerSet)) { powerSet.add (new XSet (set).add (aValue)); } } return powerSet; } }
2、WeakSet: ECMAScript 6 新增的“弱集合”(WeakSet)是一种新的集合类型,为这门语言带来了集合数据结构。WeakSet 是 Set 的“兄弟”类型,其 API 也是 Set 的子集。WeakSet 中的“weak”(弱),描述的是 JavaScript 垃圾回收程序对待“弱集合”中值的方式。 弱集合中的值只能是 Object 或者继承自 Object 的类型,尝试使用非对象设置值会抛出 TypeError。
基本API:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 const ws = new WeakSet ();const val1 = {id : 1 }, val2 = {id : 2 }, val3 = {id : 3 }; const ws1 = new WeakSet ([val1, val2, val3]); alert (ws1.has (val1)); alert (ws1.has (val2)); alert (ws1.has (val3)); const ws2 = new WeakSet ([val1, "BADVAL" , val3]); typeof ws2; const stringVal = new String ("val1" ); const ws3 = new WeakSet ([stringVal]); alert (ws3.has (stringVal)); const ws = new WeakSet (); const val1 = {id : 1 }, val2 = {id : 2 }; alert (ws.has (val1)); ws.add (val1) .add (val2); alert (ws.has (val1)); alert (ws.has (val2)); ws.delete (val1); alert (ws.has (val1)); alert (ws.has (val2)); const val1 = {id : 1 }, val2 = {id : 2 }, val3 = {id : 3 }; const ws = new WeakSet ().add (val1); ws.add (val2) .add (val3); alert (ws.has (val1)); alert (ws.has (val2)); alert (ws.has (val3));
3、弱值: WeakSet 中“weak”表示弱集合的值是“弱弱地拿着”的。意思就是,这些值不属于正式的引用,不会阻止垃圾回收。 来看下面的例子:
1 2 const ws = new WeakSet (); ws.add ({});
add()方法初始化了一个新对象,并将它用作一个值。因为没有指向这个对象的其他引用,所以当这行代码执行完成后,这个对象值就会被当作垃圾回收。然后,这个值就从弱集合中消失了,使其成为一个空集合。
1 2 3 4 5 6 7 8 9 再看一个稍微不同的例子: const ws = new WeakSet (); const container = { val : {} }; ws.add (container.val ); function removeReference ( ) { container.val = null ; }
这一次,container 对象维护着一个对弱集合值的引用,因此这个对象值不会成为垃圾回收的目标。不过,如果调用了 removeReference(),就会摧毁值对象的最后一个引用,垃圾回收程序就可以把这个值清理掉。