你不知道的Map与WeakMap

Map与Object的区别

  • Map 键名 可以是引用类型也可以是基本类型

       Obejct 键名 只能是string和symbol类型

  • Map是有序的,可迭代的

       Obejct是无序的,不可迭代的,ES2015规范,建议了浏览器厂商对对象的枚举采取有序化的操作

  • Map 有size属性

       Object 通过Object.keys().length

  • Map 可以for of Symbol.iterator 拥有可迭代协议

       Object不支持

  • Map操作方面 底层做了全名的优化(has,set,get ...)

       Object操作 没有做任何优化

  • Map没有序列化操作 JSON.stringify parse

       Object 是被支持的 -> 纯数据

如何给Map增加stringify/parse功能

//给Map增加stringify 方法
function replacer(key, value) {
    if (value instanceof Map) {
        return {
            type: 'Map',
            value: [...value]
        }
    } else {
        return value;
    }
}

//给Map增加parse方法
function reviver(key, value) {
    if (value.type === 'Map') {
        return new Map(value.value)
    }
    return value;
}



const m = new Map();
m.set('a', 1);
m.set('b', 2);
m.set({ a: 1 }, 3);
m.set([1, 2, 3], 4);

// console.log(m);

//给Map增加stringify功能
const stringRes = JSON.stringify(m, replacer);
console.log(stringRes, 'stringRes')
const stringResPas = JSON.parse(stringRes, reviver);

weeakMap

将weakMap之前呢先看一下基础知识,垃圾清除机制。

let obj1 = {a:1}; 垃圾回收机制计数+1
let obj2 = obj1  垃圾回收机制计数+1
const m = new Map();
m.set(obj1,1) 垃圾回收机制计数+1
obj1 = null //垃圾回收机制计数-1
obj2 = null; //垃圾回收机制计数-1

console.log(m) 仍然有值因为m得new map() 里面obj1 并没有释放

使用weakMap

let obj1 = {a:1}; 垃圾回收机制计数+1
let obj2 = obj1  垃圾回收机制计数+1
const m = new WeakMap();
m.set(obj1,1)  //垃圾回收机制不会在此做引用计数 =》 弱引用
obj1 = null //垃圾回收机制计数-1
obj2 = null; //垃圾回收机制计数-1

console.log(m) 仍然有值因为m得new map() 里面obj1 并没有释放

但是这里需要注意:垃圾回收机制时机是不可预测的,引用值没有被引用得时候,它有没有被回收不确定,引用值是不稳定得。可以通过setTimeout进行测试。

weakMap没有size,forEach 和clear的属性。原因是垃圾回收机制实际不可预测,像是size一会有一会没有 所以不准确。里面得成员都不确定有还是么有所以也不可能有forEach所以这些属性很难把控所以没有。

应用weakMap

一般做底层,数据收集得时候。业务深得时候。

  • 深拷贝
const obj = {
    a: 1,
    b: {
        c: 2,
        d: [12]
    }
}

const newObj = JSON.parse(JSON.stringify(obj));
obj.b.d.e = 100;
console.log(newObj, '测试内容')

上面得代码可行 但是如果对象里面有函数,上面就不会生效函数得内容

const obj = {
	...
  d:{
    ...
    f:function(){
      console.log('f')
    }
  }
}

//再或者还会有别的隐藏问题,循环引用得问题
obj.b.d.g = obj; 就会报循环引用得错误,原始内容无错,copy得内容就会报错

解决办法

function deepClone(obj) {
    if (obj === null) {
        return obj;
    }

    if (obj instanceof Date) {
        return new Date(obj)
    }

    if (obj instanceof RegExp) {
        return new RegExp(obj);
    }

    if (typeof obj !== 'object') {
        return obj
    }

    //是obj类型
    const newObj = new obj.constructor;
    for (let k in obj) {
        if (obj.hasOwnProperty(k)) {
            newObj[k] = deepClone(obj[k]);
        }
    }
    return newObj;
}

const newObj = deepClone(obj);
obj.b.d.e = 300;
console.log(newObj, 'ooo');

但是上面得方法不能解决循环引用得方法,例如obj.b.d.g = obj;这个时候就会报错。

问题是我们自身引用如果被拷贝过,其实没有必要再拷贝

解决方法: weakMap;

//解决循环死掉得
function deepClone(obj, hash = new WeakMap()) {
    if (obj === null) {
        return obj;
    }

    if (obj instanceof Date) {
        return new Date(obj)
    }

    if (obj instanceof RegExp) {
        return new RegExp(obj);
    }

    if (typeof obj !== 'object') {
        return obj
    }

    if (hash.get(obj)) {
        return hash.get(obj);
    }

    //是obj类型
    const newObj = new obj.constructor;
    //存入
    hash.set(obj, newObj);
    for (let k in obj) {
        if (obj.hasOwnProperty(k)) {
            newObj[k] = deepClone(obj[k], hash);
        }
    }
    return newObj;
}

const newObj = deepClone(obj);
obj.b.d.e = obj;
newObj.b.d.e = obj;
console.log(newObj, 'ooo');
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值