• JavaScript的Map、Set、WeakMap和WeakSet


    Object:对象,存储键值对数据,键名必须是字符串或Symbol,标准没有规定对象属性的存储顺序
    Map:映射,键名可以是任意数据类型,能记住每组键值对插入的顺序,在for..of迭代时能按照插入的顺序以[key, value]格式输出
    Array:数组,下标表现上是数字类型,但实际存储上是将数字转换成字符串作为属性值,不过引擎会对数组下标查找进行优化
    Set:集合,值唯一的数组
    WeakMap:弱引用的Map,仅接受对象作为key,如果对象本身没有其他的引用了(不包括WeakMap),那么自动从WeakMap删除
    WeakSet:弱引用的Set,仅接受对象作为value,如果对象本身没有其他的引用了(不包括WeakSet),那么自动从WeakSet删除

    Map的键和Set的值相等比较依据:(底层比较算法是SameValueZero,参见ES6规范的7.2.10小节)
    NaNNaN相等(即便NaN !== NaN => true),其他的值根据===运算符来判断是否相等。
    在ES6规范,-0+0严格相等。
    故:在Map,多个值是NaN的键会发生覆盖;在Set,多个NaN的值会只保留一个。

    Map基本操作:
    新建Map数据类型:new Map()new Map([[key1, val1], [key2, val1]])new Map(anotherMapObject)或其他能返回[key, value]格式的一维数组的可迭代对象
    插入:Map#set(key, val),返回Map对象本身,相同的键名的值会覆盖(即更新)
    读取:Map#get(key),键名不存在返回undefined
    删除:Map#delete(key),删除存在的键名返回true,删除不存在的键名返回false
    存在:Map#has(key),判断一个键是否存在
    返回长度:Map#size,这是一个getter属性
    遍历:Map#forEach((thisVal, thisKey, thisMap)=>{}, thisArg)
    清空:Map#clear(),无返回值
    获取key和value的迭代对象:Map#entries(),返回的迭代对象按照插入顺序生产值[key, value]
    获取仅key的迭代对象:Map#keys(),返回的迭代对象按照插入顺序生产值key
    获取仅value的迭代对象:Map#values(),返回的迭代对象按照插入顺序生产值value
    可从Array.from(mapObject)得到Map对象对应的二维数组(等价于Array.from(mapObject.entries())),这与使用展开运算符[...mapObject]相同。
    Map对象可以进行浅拷贝,即new Map(anotherMapObject)
    本质上,Map让你将一些额外的信息(值)与一个对象(键)相关联,而不用将这些信息实际地存储在对象本身中。

    Set基本操作:(很像Map)
    新建Set数据类型:new Set()new Set([val1, val2])new Set('string')new Set(anotherSetObject)或其他能返回value格式的可迭代对象
    插入:Set#add(value),在尾部插入
    删除:Set#delete(value),移除与给定值相同的值,如果值存在返回true,否则返回false
    存在:Set#has(value),判断值是否存在
    遍历:Set#forEach((thisVal, thisKey, thisSet)=>{}, thisArg)
    清空:Set#clear(),无返回值
    返回长度:Set#size,这是一个getter属性
    获取key和value的迭代对象:Set#entries(),返回的迭代对象按照插入顺序生产值[value, value],之所以返回两个相同元素的数组是为了与Set#entries()保持一致
    获取仅value的迭代对象:Set#values()Set#keys(),返回的迭代对象按照插入顺序生产值value
    Set迭代出来的值的顺序与插入时的一致。
    可从Array.from(setObject)得到Set对象对应的一维数组(等价于Array.from(setObject.values())),这与使用展开运算符[...setObject]相同。
    Set对象可以进行浅拷贝,即new Set(anotherSetObject)

    WeakMap的提出:
    Map的实现其实是利用了2个数组,一个保存key,一个保存value,故查找的算法复杂是O(n)。
    注意:WeakMap仅有set、get、has和delete方法,没有size属性!

    var foo = new Map();
    (function(){
    	var obj={aaa:111};
    	foo.set(obj, 'obj111Value');
    }());
    console.log(foo.size); // 1
    // 由于立即函数的作用域已不复存在,意味着无法再访问obj对象,无法再通过foo.get方法得到键obj对应的值
    // 但是可以通过`for..of`遍历出这对键值对
    // 由于保存key的数组引用了立即函数内部的obj对象,导致即便obj在外部已经不可访问,但仍旧在内存中保存着(因为存在引用),这就造成了内存泄露
    var bar = new WeakMap();
    (function(){
    	var obj={bbb:222};
    	bar.set(obj, 'obj222Value');
    }());
    console.log(bar); // bar会在下一轮GC之后变成空WeakMap
    // 由于不具备size属性和一切迭代方法,同时由于立即函数的obj无法在函数外被访问,也不能使用get方法判断,你只能信任引擎一定会将没有任何引用的obj对象从WeakMap中删除
    // Map对它的键持有强引用(不被GC忽略),而WeakMap对它的键持有弱引用(被GC忽略)
    // 不过,WeakMap对它的值(value)持有强引用,即
    // 在WeakMap中,如果一对键值对的键不存在任何引用了,这对键值对就会自动从WeakMap中删除;而如果一对键值对的值不存在除WeakMap之外的其他任何引用了,这对键值对不会从WeakMap中删除
    

    WeakMap的polyfill:

    // WeakMap的polyfill
    var WeakMap = function(){
    	this.name = '__wm__' + getUUID();
    };
    WeakMap.prototype.set = function(key, value){
    	Object.defineProperty(key, this.name, { // 重点
    		value: [key, value]
    	});
    	return this;
    };
    WeakMap.prototype.get = function(key){
    	var entry = key[this.name];
    	return entry && (entry[0] === key ? entry[1] : undefined);
    };
    // 可以看出WeakMap不再和Map一样使用双数组来存储数据,而是直接将值定义在传入的对象上,故而WeakMap只接收对象作为key
    

    WeakSet只能存储对象,且只是持有对这些对象的弱引用,即如果有对象没有再被引用,那么这个对象就会被GC,也自然而然地从WeakSet中删除,出于此,WeakSet是不可被枚举的。
    注意:WeakSet只有add、has和delete方法,没有size属性!

    《你不知道的JavaScript(下)》GitHub中文第一版对WeakMap描述:WeakMap(仅)接收对象作为键。这些对象被持有,这意味着如果对象本身被垃圾回收掉了,那么在WeakMap中的记录也会被移除。这是观察不到的,因为一个对象可以被垃圾回收的唯一方法是不再有指向它的引用,一旦不再有指向它的引用,你就没有对象引用可以用来检查它是否存在于这个WeakMap中。
    同理,WeakSet只是持有它的值。

  • 相关阅读:
    EF使用CodeFirst创建数据库和表
    EF使用CodeFirst创建数据库和表
    MVC实现实现文件流打包成压缩包
    MVC实现实现文件流打包成压缩包
    MVC实现实现文件流打包成压缩包
    Visual Studio Code 开发 .NET Core 看这篇就够了
    Visual Studio Code 开发 .NET Core 看这篇就够了
    P1438 无聊的数列
    P3380 【模板】二逼平衡树(树套树)
    SP16580 QTREE7
  • 原文地址:https://www.cnblogs.com/ryzz/p/13914786.html
Copyright © 2020-2023  润新知