趁着闲暇时间,在家研究了vue-next的源码,注意到了它对WeakMap的应用。大家应该都知道,新版Vue的实现机制和老版本相比,从defineProperty变成了Proxy,但是可能没有注意到细节上的区别。在ES6之前,前端使用Map时,通常是通过对象来模拟;对象的键值只能是字符串,即使传入的键值不是字符串形式,也会转为字符串,但是Map没有这个约束:leto={};让o1={toString(){返回1;}};设o2={};o[o1]=1;o[o2]=2;o;//{1:1,[objectObject]:2}WeakMap和Map的区别理论上的区别WeakMap的key只能是对象类型(null任何时候都不是对象,除了typeof的bug是视为对象):constm1=newMap();constwm=newWeakMap();constk1={foo:1};constk2='k2';m1.set(k1,'v1');m1.set(k2,'v2')wm。set(k1,'v1');//wm.set(k2,'v2');//TypeError:InvalidvalueusedasweakmapkeyWeakMap的key不在垃圾回收机制中。WeakMap的key引用的对象都是弱引用,即垃圾回收机制不考虑引用;一旦key没有被其他地方引用,就会被回收。正是因为WeakMap键名的不确定性,它没有keys()、values()、entries()方法,也没有size属性;另外,WeakMap没有clear()方法(一开始是有这个方法的)。前面在实际运行中提到,WeakMap和Map的一个重要区别是它的垃圾回收机制;没有证据,下面用一段代码来展示它的回收效果(因为在浏览器环境下,垃圾回收是无法通过代码来控制的,所以下面的代码通过Node.js运行,node--expose-gc以启用手动清理)://print方法formatfunctionformat(value){return`${(value/1024/1024).toFixed(2)}M`}functionprint(m){console.log(`HeapTotal:${格式(m.heapTotal)}`);console.log(`HeapUsed:${format(m.heapUsed)}`);}//手动垃圾回收global.gc();console.log('Initialization:');print(process.memoryUsage());//node中查看内存状态的方法,我们只需要关注heapTotal,heapUsedletvm=newWeakMap();letkey=newArray(20*1024*1024);vm.set(key,'foo');global.gc();console.log('回收前:');print(process.memoryUsage());键=空;//key设置为null后,只被vm键名引用global.gc();console.log('Afterrecycled:');print(process.memoryUsage());//的操作上面的代码结果://node--expose-gcweakmap-test.js//初始化://HeapTotal:4.52M//HeapUsed:1.86M//回收前://HeapTotal:166.52M//HeapUsed:161.71M//回收后://HeapTotal:10.52M//HeapUsed:1.71M如果将上面代码中的WeakMap换成Map,运行结果为:Initialization:HeapTotal:4.52MHeapUsed:1.86M回收前:HeapTotal:166.52MHeapUsed:161.71M回收后:HeapTotal:170.52MHeapUsed:161.71M使用Map时,由于数组占用的内存还没有回收,所以垃圾回收前后HeapUsed没有区别;在使用WeakMap的时候,经过垃圾回收,内存回收另外,我们在代码中创建了一个长度为20M的空数组,但是它占用的内存大约是160M,也就是说每个空元素占用的内存大小为8个字节。如果您有兴趣,请查看JavaScript数组在Chrome中占用多少内存?在浏览器中可以通过开发者工具查看使用WeakMap和Map时对内存的影响:constmap=newWeakMap();//将WeakMap换成Map后,再次点击TakeHeapSnapshot,耗时会明显增加;而且从图中可以看出array占用的内存并没有被回收。(function(){//立即执行该函数,执行后,除了map/weakmap外没有其他途径可以访问;当作为map的key时,不会回收内存;当使用时作为WeakMap的key,执行后会被回收;constarr1=newArray(20*1024*1024);constarr2=newArray(20*1024*1024);constarr3=newArray(20*1024*1024);constarr4=newArray(20*1024*1024);constarr5=newArray(20*1024*1024);constarr6=newArray(20*1024*1024);constarr7=newArray(20*1024*1024);constarr8=新数组(20*1024*1024);constarr9=新数组(20*1024*1024);constarr10=新数组(20*1024*1024);constarr11=新数组(20*1024*1024);常量arr12=新数组(20*1024*1024);常量arr13=新数组(20*1024*1024);常量arr14=新数组(20*1024*1024);常量arr15=新数组(20*1024*1024);常量arr16=新数组(20*1024*1024);常量arr17=新数组(20*1024*1024);常量arr18=新数组(20*1024*1024);map.set(arr1,'arr1');map.set(arr2,'arr2');地图.set(arr3,'arr3');map.set(arr4,'arr4');map.set(arr5,'arr5');map.set(arr6,'arr6');map.set(arr7,'arr7');map.set(arr8,'arr8');map.set(arr9,'arr9');map.set(arr10,'arr10');map.set(arr11,'arr11');map.set(arr12,'arr12');map.set(arr13,'arr13');map.set(arr14,'arr14');map.set(arr15,'arr15');map.set(arr16,'arr16');map.set(arr17,'arr17');map.set(arr18,'arr18');})();WeakMapExecutionresult:Map执行结果:WeakMap在前端项目中的应用场景,请参考阮一峰先生WeakMap-purposereference:Node.jsmemorymanagementandV8garbagecollectionmechanismWeakMap-purpose
