本章涉及:理解ES6新数据结构Set、WeakSet、Map、WeakMap理解JS中的强弱应用理解entry结构在ES6之前,JavaScript只有两种数据结构:数组和对象。准确的说,对象还不是数据结构,它的底层是由hashTable实现的(不知道对不对,听别人说的)。ES6新增了4种数据结构:Set,WeakSet,Map和弱图。接下来,让我们依次认识一下。根据MDN作为基础的SetSet对象允许您存储任何类型的唯一值,原始值或对象引用。Set对象是值的集合,您可以按照插入的顺序遍历其元素。Set中的元素只会出现一次,即Set中的元素是唯一的。Set中没有索引值。集合中值的唯一性意味着基本数据类型的值必须相等,引用数据类型的地址必须相等;但是什么?还有几个值需要特别注意:processingfor0//+0and-0console.log(+0===-0)//trueconstset=newSet()set.add(+0)set.add(-0)console.log(set)//Set(1){0}处理NaNconsole.log(NaN===NaN)//falseconstset=newSet()set.add(NaN)set.add(NaN)console.log(set)//Set(1){NaN}在Set中也被认为是相等的。Set构造函数的常用方法和属性:不接受任何参数或一个迭代器参数,并创建一个Set实例。Set.prototype.size:返回集合中元素的数量。Set.prototype.add(value):在Set对象的末尾添加一个元素。返回集合对象。Set.prototype.clear():移除Set对象中的所有元素,无返回值。set.prototype.delete(value):从集合中删除等于该值的元素,返回boolean类型Set.prototype.has(value):判断集合中是否存在元素,返回boolean类型遍历条目:保持与Map返回的格式相同,key和value的值相同。forEach:遍历Set中的每一个元素。values:同上代码democonstarr=[4,3,2,1,5]//constructorconstset=newSet(arr)//sizeconsole.log(set.size)//5//addconsole.log(set.add(6))//Set(6){4,3,2,1,5,6}//deleteconsole.log(set.delete(1))//true//hasconsole.log(set.has(1))//false//clearconsole.log(set.clear())//如果遍历undefined,则不敲。WeakSetWeakSet对象允许您将弱持久对象存储在无法在内部复制的集合中。上面的概念提到了一个weakhold,怎么理解呢?请参阅下面的JavaScript中的强引用和弱引用。WeakSet与Set的区别WeakSet只能存储对象类型,不能存储基本数据类型;WeakSet对元素的引用是弱引用,如果一个对象没有其他引用,那么GC就可以回收该对象;不被列举。WeakSet常用方法WeakSet.prototype.add(value):添加一个元素,返回WeakSet对象本身;WeakSet.prototype.delete(value):从WeakSet中删除等于这个值的元素,返回boolean类型;WeakSet.prototype.has(value):判断某个元素是否存在于WeakSet中,返回boolean类型;无法遍历。使用场景很少(代码量小,可能没遇到过)。MapMap对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或基元)都可以用作键或值。在map之前,只要想到键值对的形式,就一定会想到对象。是的,没有异议。那么Map和Object有什么区别呢?对象的key值只能是字符串,后加的symbol类型。但是,Map支持所有类型。对象处理对象为关键场景(a)//{'[objectObject]':'bbb'}可见,会先将object转换成字符串[objectObject],将字符串作为key值。Map构造函数中的属性和方法:不接受任何参数或条目结构的参数,并创建一个Set实例。(要了解条目结构,请参阅下面的了解条目结构)。Map.prototype.size:返回Map对象中键值对的数量。Map.prototype.clear():移除Map对象中的所有键值对。Map.prototype.delete(key):移除Map对象中指定的键值对,如果该键值对存在则返回true,否则返回false。Map.prototype.get(key):返回与key关联的值,如果没有关联值则返回undefined。Map.prototype.has(key):返回一个布尔值,表示Map对象中是否存在与key关联的值。Map.prototype.set(key,value):设置Map对象中指定键key关联的value值,返回Map对象。遍历for...of..keysvaluesentriesforEach代码演示constmap=newMap([["name","copyer"]]);//sizeconsole.log(map.size);//1//setmap.set(1,"我是一个数字");//getconsole.log(map.get(1));//我是一个数字//hasconsole.log(map.has(1));//true//deleteconsole.log(map.delete(1));//true//clear//console.log(map.clear());//forEachmap.forEach((value,key)=>{console.log(value,key)//copyername})//for...of...for(const[key,value]ofmap){console.log(key,value)//namecopyer}Map和object的比较借鉴自MDNUnexpectedkeyscomparedtoMapObjectMapdoesnot默认情况下包含任何键。仅包含显式插入的键。一个Object是有原型的,原型链上的key可能会和你自己在object上设置的key冲突。键的类型Map的键可以是任何值,包括函数、对象或任何基本类型。对象的键必须是字符串或符号。键顺序Map中的键是有序的。因此,在迭代时,Map对象按插入顺序返回键。虽然Object的键当前是有序的,但情况并非总是如此,而且这种排序很复杂。因此,最好不要依赖属性的顺序。SizeMap中键值对的个数可以很方便的通过size属性获取。Object的key-value对的个数只能手动计算。IterativeMap是可迭代的,所以可以直接迭代。Object没有实现可迭代协议,所以使用JavaScript的for...of表达式并不能直接迭代对象。在频繁添加或删除键值对的场景下性能更好。没有针对频繁增删键值对的场景进行优化。序列化和解析没有元素序列化和解析支持。使用JSON.stringify()从对象到JSON的本机序列化支持。使用JSON.parse()从JSON到Object的原生解析支持。其实通过上面的对比,大部分map都是优先于object的,但是在开发过程中,基本都是用object(可能是开发水平不够)map和array的转换constkvArray=[["key1","value1"],["key2","value2"]];//使用常规的Map构造函数将键值对的二维数组转换为Map对象constmyMap=newMap(kvArray);myMap.得到(“key1”);//返回值为"value1"//使用Array.from函数将一个Map对象转换为键值对的二维数组console.log(Array.from(myMap));//OutputSamearrayaskvArray//一种更简洁的方式来完成与上面相同的事情,使用传播运算符console.log([...myMap]);//或者在迭代器上使用Array.from获取键或值,然后得到一个只包含键或值的数组console.log(Array.from(myMap.keys()));//output["key1","key2"]WeakMapWeakMap对象是一组键/值对,其中的键是弱引用的。它的键必须是对象,而值可以是任意的。WeakMap和Map的区别WeakMap的key值只能是对象,不能是其他类型;一个WeakSet对一个元素的引用是一个弱引用,如果一个对象没有其他引用,那么GC就可以回收这个对象;它不能用于枚举。WeakMap常用的方法构造器:不接受任何参数或有参数的entries结构,创建一个Set实例。(要了解条目结构,请参阅下面的了解条目结构)。WeakMap.prototype.delete(key):移除WeakMap对象中指定的键值对,如果该键值对存在则返回true,否则返回false。WeakMap.prototype.get(key):返回与key关联的值,如果没有关联值则返回undefined。WeakMap.prototype.has(key):返回一个布尔值,表示与key关联的值是否存在于WeakMap对象中。WeakMap.prototype.set(key,value):设置WeakMap对象中指定键key关联的value值,返回Map对象。使用场景在Vue3响应式拦截中,使用了WeakMap。了解JavaScript中的强引用和弱引用JavaScript中的对象,只要不被引用,就会被垃圾回收机制回收。强引用先看代码letobj={name:"copyer",age:23};constnewObj=obj;obj=null;console.log(obj);//nullconsole.log(newObj);//{name:'copyer',age:23}上面的代码应该很简单。简单的一个对象obj,将obj的引用赋值给另一个变量newObj,然后清除obj,并打印两者。那么记忆的形式呢?为什么obj为null,newObj还有值?创建一个Obj对象,在堆中产生一个内存地址0x100,obj在栈中的值:0x100并将引用赋值给newObj,那么它的值也是0x100。当执行obj=null时,obj与堆内存的连接只是断开了。newObj的连接没有断开,所以obj为null,但是newObj是有值的。当在内存中打开的地址,只要被别人指向,就不会被垃圾回收机制回收。这是一个很强的参考。(强方)从字面意思上来说,弱引用就是来自弱方,即使指向了某个引用,但是垃圾回收机制看不起你,你太弱了,强行回收内存。WeakSet和WeakMap是弱引用。WeakMap实例:letobj={name:"copyer",age:23};letweakMap=newWeakMap([[obj,obj]])console.log(weakMap.get(obj))//{name:"copyer",age:23}//ifobj=nullconsole.log(weakMap.get(obj))//undefined定义了一个obj对象,会在内存中开辟一个地址,WeakMap的参数传递中,obj的内存被引用中指向的地址。但是,当obj=null时,连接断开。按理说还有其他地方被引用了,就不回收了。但如果是弱引用,内存中同一个地址会被回收,WeakMap参数引用不会指向它,所以是undefined。强引用总结:只要有引用,就不会被回收。弱引用:即使有引用点,也会被回收。(WeakSet和WeakMap是JS弱引用的体现)要理解entrys结构到底是什么,只要调用Object.entries()方法即可。constobj={name:'copyer',age:23,height:180}console.log(Object.entries(obj))//[['name','copyer'],['age',23],['height',180]]Object.entries()方法返回给定对象自身可枚举属性的键值对数组。(像一个二维数组)它的格式:[[key,value],[key,value]...]
