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');