深入理解ES6--7.Set和Map

原创文章&经验总结&从校招到A厂一路阳光一路沧桑

详情请戳www.codercc.com

image

主要知识点: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中有三个参数:

  1. 元素值;

  2. 元素索引;

  3. 将要遍历的对象;

     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之间的重要差异:

  1. 对于Weak Set实例,若调用了add()方法时传入了非对象的参数,则会抛出错误。如果在has()或者delete()方法中传入了非对象的参数则会返回false;
  2. Weak Set不可迭代,因此不能用于for-of循环;
  3. Weak Set 无法暴露出任何迭代器(例如 keys() 与 values() 方法) ,因此没有任何编程手段可用于判断 Weak Set 的内容;
  4. Weak Set没有forEach()方法;
  5. Weak Set没有size属性;

3. ES6中的Map

ES6中提供了Map数据结构,能够存放键值对,其中,键的去重是通过Object.is()方法进行比较,键的数据类型可以是基本类型数据也可以是对象,而值也可以是任意类型数据。

对Map的操作

  1. 使用set()方法可以给Map添加键值对

     let map = new Map();
     map.set('title','hello world');
     map.set('year','2018');
     
     console.log(map.size); //2
    

通过set()方法往Map中增加了两个键值对后,可以看到Map的大小就为2;

  1. 通过get()方法可以从Map中提取值

     let map = new Map();
     map.set('title','hello world');
     map.set('year','2018');
     
     console.log(map.get('title')); // hello world
    
  2. 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方法,该方法也接收一个回调函数,该回调函数有三个参数:

  1. 键值对的键;

  2. 键值对的值;

  3. 当前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的操作

  1. 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
  1. 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. 总结

  1. Set 是无重复值的有序列表。根据 Object.is()方法来判断其中的值不相等,以保证无重复。 Set 会自动移除重复的值,因此你可以使用它来过滤数组中的重复值并返回结果。 Set并不是数组的子类型,所以你无法随机访问其中的值。但你可以使用has() 方法来判断某个值是否存在于 Set 中,或通过 size 属性来查看其中有多少个值。 Set 类型还拥有forEach()方法,用于处理每个值。

  2. Weak Set 是只能包含对象的特殊 Set 。其中的对象使用弱引用来存储,意味着当 Weak Set中的项是某个对象的仅存引用时,它不会屏蔽垃圾回收。由于内存管理的复杂性, Weak Set的内容不能被检查,因此最好将 Weak Set 仅用于追踪需要被归组在一起的对象。

  3. Map 是有序的键值对,其中的键允许是任何类型。与 Set 相似,通过调用 Object.is()方法来判断重复的键,这意味着能将数值 5 与字符串 "5" 作为两个相对独立的键。使用set() 方法能将任何类型的值关联到某个键上,并且该值此后能用 get() 方法提取出来。Map 也拥有一个 size 属性与一个 forEach() 方法,让项目访问更容易。

  4. Weak Map 是只能包含对象类型的键的特殊 Map 。与 Weak Set 相似,键的对象引用是弱引用,因此当它是某个对象的仅存引用时,也不会屏蔽垃圾回收。当键被回收之后,所关联的值也同时从 Weak Map 中被移除。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,277评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,777评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,946评论 0 245
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,271评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,636评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,767评论 1 221
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,989评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,733评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,457评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,674评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,155评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,518评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,160评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,114评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,898评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,822评论 2 280
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,705评论 2 273

推荐阅读更多精彩内容