主要知识点: Set 的基本操作, Weak Set,Map 的基本操作, Weak Map
Set 和 Map 知识点
1.ES6 中的 Set
ES6 中提供了 Set 数据容器, 这是一个能够存储无重复值的有序列表.
创建 Set
通过 new Set() 可以创建 Set, 然后通过 add 方法能够向 Set 中添加数据项:
- //Set
- let set= new Set();
- set.add(1);
- set.add('1');
- console.log(set.size);//2
Set 内部使用 Object.is() 方法来判断两个数据项是否相等, 唯一不同的是 + 0 和 - 0 在 Set 中被判断为是相等的.
同时可以使用数组来构造 Set, 或者说具有迭代器的对象都可以用来构造 Set, 并且 Set 构造器会确保不会存在重复的数据项:
- let set = new Set([1,2,3,3,3,3]);
- console.log(set.size);//3
检查某个值是否存在于 Set 中
可以使用 has() 方法来判断某个值是否存在于 Set 中:
- let set = new Set([1,2,3,3,3,3]);
- console.log(set.has(5)); //false
删除值
使用 delete() 方法从 Set 中删除某个值, 或者使用 clear() 方法从 Set 中删除所有值:
- let set = new Set([1,2,3,3,3,3]);
- console.log(set.size);//3
- console.log(set.has(5)); //false
- set.delete(1);
- console.log(set.has(1)); //false
- console.log(set.size); //2
forEach() 方法
可以使用 forEach 方法来遍历 Set 中的数据项, 该方法传入一个回调函数 callback, 还可以传入一个 this, 用于回调函数之中:
回调函数 callback 中有三个参数:
元素值;
元素索引;
将要遍历的对象;
- let set = new Set([1,2,3,3,3,3]);
- set.forEach(function (value,key,ownerSet) {
- console.log(value);
- console.log(key);
- })
Set 中的 value 和 key 是相同的, 这是为了让 Set 的 forEach 方法和数组以及 Map 的 forEach 方法保持一致, 都具有三个参数.
在 forEach 方法中传入 this, 给回调函数使用:
- let set = new Set([1,2,3,3,3,3]);
- let operation ={
- print(value){
- console.log(value);
- },
- iterate(set=[]){
- set.forEach(function(value,key,ownerSet){
- this.print(value);
- this.print(key);
- },this);
- }
- }
- operation.iterate(set);
输出: 1 1 2 2 3 3
如果回调函数使用箭头函数的话, 就可以省略 this 的入参, 这是因为箭头函数会通过作用域链找到当前 this 对象, 将上面的示例代码使用箭头函数来写:
- let set = new Set([1,2,3,3,3,3]);
- let operation ={
- print(value){
- console.log(value);
- },
- iterate(set=[]){
- set.forEach((value,key)=>{
- this.print(value);
- this.print(key);
- })
- }
- }
- operation.iterate(set);
将 Set 转换成数组
将数组转换成 Set 十分容易, 可以将数组传入 Set 构造器即可; 而将 Set 转换成数组, 需要使用扩展运算符. 扩展运算符能将数组中的数据项切分开, 作为独立项传入到函数, 如果将扩展运算符用于可迭代对象的话, 就可以将可迭代对象转换成数组:
- let [...arr]=set;
- console.log(arr); // [1,2,3]
- Weak Set
Set 在存放对象时, 实际上是存放的是对象的引用, 即 Set 也被称之为 Strong Set. 如果所存储的对象被置为 null, 但是 Set 实例仍然存在的话, 对象依然无法被垃圾回收器回收, 从而无法释放内存:
- let set = new Set();
- let key={};
- let key2 = {};
- set.add(key);
- set.add(key2);
- console.log(set.size); //2
- key=null;
- console.log(set.size); //2
可以看出就算对象 key 置为 null, 但是由于是强引用的方式, Set 实例还存在, 对象 key 依然不会被回收.
如果想让对象 key 正常释放的话, 可以使用 Weak Set, 此时, 存放的是对象的弱引用, 当对象只被 Set 弱引用的话, 并不会阻止对象实例被回收. Weka Set 同 Set 的用法几乎一致. 可以使用 add() 方法增加数据项, 使用 has() 方法检查 Weak Set 中是否包含某项, 以及使用 delete() 方法删除某一项.
- let set = new WeakSet();
- let key = {};
- set.add(key);
- console.log(set.has(key)); //true
- set.delete(key);
- console.log(set.has(key)); //false
但需要注意的是: Weak Set 构造器不接受基本类型数据, 只接受对象. 同样的可以使用可迭代的对象如数组, 来作为构造器参数, 来创建 Weak Set.
Weak Set 和 Set 之间的差异
对于 Weak Set 和 Set 之间的重要差异:
对于 Weak Set 实例, 若调用了 add() 方法时传入了非对象的参数, 则会抛出错误. 如果在 has() 或者 delete() 方法中传入了非对象的参数则会返回 false;
Weak Set 不可迭代, 因此不能用于 for-of 循环;
Weak Set 无法暴露出任何迭代器 (例如 keys() 与 values() 方法) , 因此没有任何编程手段可用于判断 Weak Set 的内容;
Weak Set 没有 forEach() 方法;
Weak Set 没有 size 属性;
3. ES6 中的 Map
ES6 中提供了 Map 数据结构, 能够存放键值对, 其中, 键的去重是通过 Object.is() 方法进行比较, 键的数据类型可以是基本类型数据也可以是对象, 而值也可以是任意类型数据.
对 Map 的操作
使用 set() 方法可以给 Map 添加键值对
- let map = new Map();
- map.set('title','hello world');
- map.set('year','2018');
- console.log(map.size); //2
通过 set() 方法往 Map 中增加了两个键值对后, 可以看到 Map 的大小就为 2;
通过 get() 方法可以从 Map 中提取值
- let map = new Map();
- map.set('title','hello world');
- map.set('year','2018');
- console.log(map.get('title')); // hello world
has(),delete() 以及 clear() 方法
为了和 Set 的操作保持一致, Map 中同样有 has() 方法, 用来检查某个数据项是否存在于 Map 中, 使用 delete 方法可以从 Map 中删除一个数据项, 使用 clear 方法可以删除 Map 中所有的数据项
- let map = new Map();
- map.set('title','hello world');
- map.set('year','2018');
- console.log(map.has('year')); //true
- map.delete('title');
- console.log(map.has('title')); //false
- map.clear();
- console.log(map.size); //0
Map 的初始化
与 Set 的初始化一样, Map 也可以用数组来初始化 Map, 该数组中的每一个数据项也是数组, 数组的第一个数据项代表键值对的键, 第二个数据项是键值对的值:
- // 使用数组来创建 Map
- let map = new Map([['title','hello world'],['year','2018']]);
- console.log(map.has('title')); //true
- console.log(map.has('year')); //true
- console.log(map.size); //2
Map 的 forEach 方法
与 Set 一样, Map 也拥有 forEach 方法, 该方法也接收一个回调函数, 该回调函数有三个参数:
键值对的键;
键值对的值;
当前 Map 对象引用;
- let map = new Map([['title','hello world'],['year','2018']]);
- map.forEach((value,key,ownerMap)=>{
- console.log(value);
- console.log(key);
- });
- hello world
- title
- 2018
- year
与 Set 的 forEach 一样, 可以在回调函数中传入 this 引用.
Weak Map
Weak Map 对 Map 而言, 就像是 Weak Set 相对于 Set 一样: Weak Map(或者 Weak Set) 都是存储对象弱引用的方式, 在 Weak Map(或者 Weak Set) 中, 所有的键都必须是对象 (尝试使用非对象的键会抛出错误), 而且这些对象都是弱引用, 不会干扰到垃圾回收. 当 Weak Map 中的键在 Weak Map 之外不存在引用时, 该键值对会被移除.
Weak Map 的操作
Weak Map 的初始化
Weak Map 的键必须是对象, 值可以是任意类型, 初始化同 Map 一样, 也可是使用数组来创建一个 Weak Map :
- // 使用数组来创建一个 Weak Map
- let key = {};
- let key2 = {};
- let map = new WeakMap([[key,'hello'],[key2,'world']]);
- console.log(map.get(key)); //hello
- console.log(map.get(key2)); //world
has 方法以及 delete 方法
与 Map 一样, 可以使用 has() 方法来检查 Weak Map 中是否存在某一个键值对, 使用 delete() 方法可以删除一个键值对. clear() 方法不存在, 这是因为没必要对键进行枚举, 并且枚举 Weak Map 也是不可能的, 这与 Weak Set 相同:
- let key = {};
- let key2 = {};
- let map = new WeakMap([[key,'hello'],[key2,'world']]);
- map.delete(key);
- console.log(map.has(key)); //false
Weak Map 的用法与局限性
当决定是要使用 Weak Map 还是使用正规 Map 时, 首要考虑因素在于你是否只想使用对象类型的键. 如果你打算这么做, 那么最好的选择就是 Weak Map . 因为它能确保额外数据在不再可用后被销毁, 从而能优化内存使用并规避内存泄漏.
要记住 Weak Map 只为它们的内容提供了很小的可见度, 因此你不能使用 forEach() 方法, size 属性或 clear() 方法来管理其中的项. 如果你确实需要一些检测功能, 那么正规 Map 会是更好的选择, 只是一定要确保留意内存的使用.
4. 总结
Set 是无重复值的有序列表. 根据 Object.is() 方法来判断其中的值不相等, 以保证无重复. Set 会自动移除重复的值, 因此你可以使用它来过滤数组中的重复值并返回结果. Set 并不是数组的子类型, 所以你无法随机访问其中的值. 但你可以使用 has() 方法来判断某个值是否存在于 Set 中, 或通过 size 属性来查看其中有多少个值. Set 类型还拥有 forEach() 方法, 用于处理每个值.
Weak Set 是只能包含对象的特殊 Set . 其中的对象使用弱引用来存储, 意味着当 Weak Set 中的项是某个对象的仅存引用时, 它不会屏蔽垃圾回收. 由于内存管理的复杂性, Weak Set 的内容不能被检查, 因此最好将 Weak Set 仅用于追踪需要被归组在一起的对象.
Map 是有序的键值对, 其中的键允许是任何类型. 与 Set 相似, 通过调用 Object.is() 方法来判断重复的键, 这意味着能将数值 5 与字符串 "5" 作为两个相对独立的键. 使用 set() 方法能将任何类型的值关联到某个键上, 并且该值此后能用 get() 方法提取出来. Map 也拥有一个 size 属性与一个 forEach() 方法, 让项目访问更容易.
Weak Map 是只能包含对象类型的键的特殊 Map . 与 Weak Set 相似, 键的对象引用是弱引用, 因此当它是某个对象的仅存引用时, 也不会屏蔽垃圾回收. 当键被回收之后, 所关联的值也同时从 Weak Map 中被移除.
来源: http://www.jianshu.com/p/af78964c33e2