彻底搞懂WeakMap和Map
admin
2024-01-19 02:30:31
0

一 、Map

Map是一种叫做字典的数据结构,Map 对象保存不重复键值对,并且能够记住键的原始插入顺序

  • Map的属性和方法* 属性: size: 返回所包含的键值对长度* 操作方法:* set(key,val): 添加新键值对* get(key): 通过传入键查找并返回对应值* has(key): 判断是否存在该键* delete(key):删除该键值对* clear:清空
//创建map结构
const map = new Map();
//添加键
map.set('name','clt').set('gender','girl').set('age',20);
//获取size
console.log(map.size); //3
//判断键
console.log(map.has('age')); //20
//获取值
console.log(map.get('age')); //true
//清空map
map.clear()
console.log(map.size); //0 

✍问题一:能不能对Map设置对象属性?

  • 你带着疑问输入了以下代码,发现没有报错而且确实打印出来了,但是定睛一看,size=0````const map = new Map();map.gender = 'girl';map['name'] = 'clt';console.log(map); //{gender: 'girl', name: 'clt', size: 0} ```* 因为这种方法只能说是对象的特性,但是数据并没有进入map的数据结构,也就是它并没有被map存储起来,所以size`为0,同样其他操作方法也不生效;所以答案是可以,但是没有用console.log(map.get('name')) //undefinedconsole.log(map.has('gender')); //false #### ✍问题二:既然是存储不重复的数据,那么是如何判断是否相等?

  • 主要是判断键是否相等

  • 键的判断是基于零值相等(SameValueZero

  • ===的区别为对于===而言NaN !== NaN, 而对于零值运算而言两者是相等

这里我看过有一些说法是键的比较使用Object.is(),我感觉不太对?,Object.is()认为+0,-0不相等,而Map是认为相等的

const map = new Map();
map.set(+0,'123').set(-0,'345');
console.log(map); //0,345
console.log(Object.is(-0,+0)) //false 

✍问题三:Map和Object的区别在哪里?

  • 键值Map可以是任意值,包括函数,对象,基本类型,而对象只能是String或者Symbol或者整数* 键值对长度Map可以直接通过size属性获取键值对长度,而Object没有提供该属性,需要手动遍历计算* 迭代Map是可迭代的,有内置迭代器,但是Object没有实现迭代协议,没有内置迭代器console.log(typeof obj[Symbol.iterator]); //undefined console.log(typeof map[Symbol.iterator]); //function * 性能Map在频繁增删键值对的场景下表现更好,而Object在频繁添加和删除键值对的场景下未作出优化* 序列化JSON支持Object,但是尚未支持Map````const obj = {name: 'clt',age: 20}const map = new Map();map.set('name','clt').set('age',20);console.log(JSON.stringify(obj)); //{"name":"clt","age":20}console.log(JSON.stringify(map));//{} ```* **有序**:Map是有序的,但是Object`不能保证是有序的* Map有序我们前面已经提过了,试一下Object是否能够保证有序//比如我创建一个如下的Objectconst o = Object.create(null, {m: {value: function() {}, enumerable: true},"2": {value: "2", enumerable: true},"b": {value: "b", enumerable: true},0: {value: 0, enumerable: true},[Symbol()]: {value: "sym", enumerable: true},"1": {value: "1", enumerable: true},"a": {value: "a", enumerable: true},}); * 直接打印结果(chrome,这个结果在不同浏览器上不一定一致)

  • 向Object和Ma插入新键值对的消耗相当,但是一般插入Map会比较快一点,所以如果代码涉及大量插入操作,那么Map的性能更加

  • 当我们只需要一个简单的可查找存储结构时,Map相比Object更具优势,它提供了所有基本操作,但是如果涉及大量查找情况下,可能选择Object会好一点

  • 如果涉及大量删除操作,美美选择Map啦

问题五:上面提到了可以迭代,那么是怎么迭代呢

  • Map 可以使用 for..of 循环来实现迭代//创建map结构const map = new Map();//添加键map.set('name','clt').set('gender','girl').set('age',20);for(let [key,item] of map) {console.log(key +'='+ item)} * Map 也可以通过 forEach() 方法迭代,传入回调函数依次迭代每个键值对,有可选的第二个参数,用于重写回调内部this的值//创建map结构const map = new Map();//添加键map.set('name','clt').set('gender','girl').set('age',20);map.forEach((value, key) => {console.log(key + '=' + value)}) > 这种行为跟在数组上调用forEach()方法略有不同,后者的回调函数会按照数值索引的顺序接收到每一个项,#### ✍ 问题六、是否可以一次性将大量数据添加到Map

  • 可以在构造Map的时候传入数组来初始化,该数组的每一项也必须是数组,内部首个项作为键,第二项作为对应值const arr = [['name', 'mouche'] ,[ 'age', 20]];const map = new Map(arr);for(let [key, value] of map) {console.log(key+'='+ value);} //name=mouche, age=20 > Map就说到这里了,你以为我要说WeakMap? 漏!搞定了垃圾回收才能搞懂WeakMap,所以我们就先来看看这个是啥玩意

二、垃圾回收

  • 原因:如果存在大量不被释放的内存(堆/栈/上下文),页面性能会变得很慢。垃圾回收顾名思义就是回收垃圾嘛,那么当某些代码操作不能被合理释放,就会造成内存泄漏,所以这个时候垃圾回收就出来发挥作用了
  • 浏览器垃圾回收机制有两种,我们分别来看看他们是啥玩意

1、标记清理

  • 2012年后所有浏览器都使用了这种策略* 垃圾回收器,在运行的时候会给存储在内存中的所有变量都加上标记* 去掉环境中的变量以及被环境中的变量引用的变量的标记* 此时还被加上标记的会被视为准备删除的变量。* 垃圾回收器完成内存清除工作,销毁那些带标记的值并回收他们所占用的内存空间
  • 缺点:地址不连续,空间碎片化

2、引用计数

  • 弊端较多,IE9之前采用
  • 对每个值记录其被引用的次数,通过最后对次数的判断来决定是否保留
  • 最大问题:无法解决循环引用无法回收的问题

三、WeakMap

  • WeakMap 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象(null除外),而值可以是任意的
const wm = new WeakMap();
wm.set(null,'123'); 
  • 弱引用:是指不能确保其引用的对象不会被垃圾回收器回收的引用。一个对象若只被弱引用所引用,则被认为是不可访问(或弱可访问)的,并因此可能在任何时刻被回收
  • 也就是说,当WeakMap键所指对象没有其他地方引用的时候,它会被垃圾回收机制回收掉

理解了垃圾回收机制再看这句话是不是就没有那么迷糊啦,拿捏🤏

  • WeakMap 不支持迭代以及 keys()values()entries() 方法
  • WeakMap的方法* get(key):获取键对应值* set(key,value):存储键值对* delete(key): 删除键值对* has(key): 判断是否有该键值对

问题一:既然已经有map了,那么WeakMap出现的原因是什么🤡

  • 那么就先说一下map的问题;map通过使其四个API方法共用两个数组(一个存放键,一个存放值)来实现。给这种map设置值时会同时将键和值添加到这两个数组的末尾。从而使得键和值的索引在两个数组中相对应。当从该map取值的时候,需要遍历所有的键,然后使用索引从存储值的数组中检索出相应的值
  • 这就导致了无论是赋值还是搜索都需要遍历真个数组,时间复杂度为O(n)
  • 同时也可能导致内存泄漏,因为数组会一直引用这每个键和值,导致无法垃圾回收机制无法在他们没有其他引用的时候进行回收

问题二:为什么不支持迭代

  • 当键所指对象没有被其他地方引用的时候就会被回收,那么没有方法能给出所有的 key,即它的结果是不确定的,所以就没有必要提供迭代方法,所以也没有clear方法

✍ 问题三:WeakMap怎么用

DOM节点元数据
  • 因为WeakMap不会阻碍垃圾回收,所以非常适合保存关联元数据const wm = weakMap();cons loginButton = document.querySelector('#login');wm.set(loginButton,{disabled:true}) * 如上使用WeakMap,当节点从DOM树被删除后,垃圾回收程度就可以立即释放其内存(如果没有其他地方引用),但是如果你使用Map的话,即时节点删除后,由于映射中还保存着按钮的引用,所以DOM节点依旧会留在内存
私有变量
  • 先说一下ES6是如何创建私有变量,此处使用IIFE,含有privateDataprivateId两个私有变量,当Person构造器被使用的时候,一个不可枚举,不可配置,不可写入的_id属性就被添加了。但是最大的问题是privateData里面的数据永不会消失,因为在对象实例被销毁的时候没有任何方法可以获取这个数据,所以privateData就会就永远会包含多余的数据
const Person = (function() {const privateData = {};letprivateId = 0;function Person(name) {Object.defineProperty(this,'_id' , {value:privateId++});privateData[this._id] = {name}}Person.prototype.getName = function() {return privateData[this._id];}return Person;
}()) 
  • 可以使用WeakMap来解决这个问题,由于Person实例本身能被作为键来使用,所以就没有必要记录ID,当Person构造器被调用时,this作为键,包含数据的对象即成了对应的值,getName()能够提取其私有信息。当私有信息与之关联的对象实例被销毁的时候,私有信息也会同时被销毁,也就解决了上述的问题
const Person = (function(){const privateData = new WeakMap();function Person(name) {privateData.set(this,{name});}Person.prototype.getName = function() {return privateData.get(this).name;}return Person
}())
const person = new Person('123');
console.log(person.getName()) //123 
) {return privateData.get(this).name;}return Person
}())
const person = new Person('123');
console.log(person.getName()) //123 

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

相关内容

热门资讯

36年老宾馆迎“新生” 24小时空调热水,高速Wi-Fi全覆盖,柔软的席梦思大床睡香香……三星级酒店“标双”客房拎包入住,这...
原创 跟... 有了昨天导航出问题迟到的教训,今天早早吃完早餐出门,前天没有白探路,今天乘坐地铁很顺利,提早半小时到...
长沙机场上演“怀化风情秀” 强... 为深入贯彻落实省委、省政府关于加快建设世界旅游目的地的决策部署,深度践行“以文塑旅、以旅彰文”的发展...
贵旅数网公司“黄小西”旅游服务... 本文转自:人民网-贵州频道日前,由文化和旅游部科技教育司指导,中国文化传媒集团、中电信文宣科技(北京...
2025茶餐厅品类发展报告:近... 文 | 红餐智库 茶餐厅作为从香港走向全国的经典美食,经历了多个发展阶段。近年来,受到多方面因素的...
自斟自饮,是一个人喜欢喝酒的重... 换句话说:判断一个人是不是真正爱酒、好酒,就看他平时有没有独酌的习惯就行了。 李太白无疑是爱酒的,...
自制河北炒酸奶,加入坚果水果的... 在炎炎夏日,自制一份融合河北特色与健康理念的炒酸奶,无疑是一场味蕾与身心的清凉之旅。 制作这份美味,...
香到舔盘的土豆丝饼!3步搞定,... 早上煎一盘金黄酥脆的土豆丝饼,咬一口外脆里软,咸香直往嘴里窜,配杯热豆浆直接幸福到跺脚!关键这玩意儿...
九道烧椒味型的川菜 烧椒是四川独特而美妙的吃法,烧椒是什么意思,你知道吗?烧椒就是把青脆的辣椒或者尖椒放在火上烧,烧软烧...
章贡高新区管委会与江西普圆食品... 2025年9月10日,章贡高新区与上海普圆食品有限公司就“江西普圆食品有限公司健康轻食投资合作”项目...
“豆橛子馅”月饼真来了,山东一... “山东豆橛子”的风 终究还是吹到了月饼界 青岛市城阳区 一家月饼生产企业 今年推出新品—— 豆角肉馅...
亲亲食品|出发前,奶奶坚持要亲... 近日,一则关于亲情的温暖故事悄然登上微博郑州同城榜热搜,话题#孙女上大学行李箱被奶奶塞满零食#引发广...
今日神图 | 假酒喝多了,真酒... 吃不到新鲜鸭血 还吃不到新鲜鸭吗? 买个鸭子回家随便吃 绿牛肉说明新鲜
原创 秋... 导语:秋老虎肆虐没有胃口?这道菜尝试一下,清凉又解腻,做法超简单! 秋老虎来势汹汹!初秋时节,暑气虽...
四川旅游小包团5天4晚报价咨询... 作为一个热爱旅行的驴友,每次踏上新的旅程,都像是在翻开一本未知的故事书,而这次四川之行,无疑是我旅行...
广西6日游价格,情侣到桂林玩6... 桂林,这座拥有着千年历史的文化名城,以其独特的喀斯特地貌闻名遐迩。“桂林山水甲天下”,这句广为流传的...
广西地接社跟团6日价格多少,桂... 嘿,宝子们!你们有没有幻想过一场“舟行碧波上,人在画中游”的绝美之旅?那桂林绝对是实现这场幻想的不二...
报团去四川玩4天多少钱一人?四... 四川,这片充满魅力的土地,一直是我心心念念的旅行目的地。它有着壮丽的自然风光,如九寨沟的多彩海子、峨...
国庆去安徽3日游费用,黄山哪个... 黄山,作为中国著名的风景名胜区,以其奇松、怪石、云海、温泉四绝闻名于世,一直是众多游客向往的旅游胜地...