小酌ObjectMap和WeakMap
Posted 恪愚
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小酌ObjectMap和WeakMap相关的知识,希望对你有一定的参考价值。
Object
对于普通Object,它的优势在于存、取元素,使用非常方便,可直接用字面量方式创建;而且里面属性值可以是不同类型:
let obj={};
obj.name='mxc';
obj.age=18;
console.log(obj);
但这不是今天的重点。
对于 Object,删除其中的属性有两种方式:delete
操作符和 =undefined
。
delete
delete 会从某个对象上移除指定属性。成功为 true,否则为false:
delete obj.age;
但这有几点不足之处:
- 如果你试图删除不存在的属性,delete 不会起任何作用,但仍返回true
- delete 不能删除全局属性/函数
- delete 不能删除内置对象的属性
- delete 只删除自身属性,而不管原型链上的同名属性 —— 这会导致一些问题:属性被删除成功但仍然可访问
console.log(obj);
delete obj.sex;
delete obj.valueOf();
obj.__proto__.age=19;
console.log(obj);
console.log(obj.age);
在数组中使用 delete 时,它会将某一项删掉,但会留下一个“空位”。即:delete 不会改变数组长度。
let arr=[1,2,3,4,5];
delete arr[2];
console.log(arr);
=undefined
如果你小心使用,它的效率是 delete 的100倍(V8之后做了优化)。但它却并不是这个问题的正解!笔者猜测是因为“undefined”的特殊性:
obj.name="undefined";
console.log(obj);
undefined 被认为是一个存在的值,它本身也可以用作属性名存在。
Map
es6提出的 Map 在一些情况下确实是不错的选择:Map是一种存储着许多键值对的有序列表,其中的键名和对应值支持所有的数据类型。
Map中键名的等价性是通过调用 Object.is()
来实现的 —— 它可以被看做“更严格的==
、和更宽松的===
”。比如数字5和字符“5”就会被判定为两个不同的键、而NaN
和NaN
也会被判定为两个不同的键。这与对象不太一样,因为对象中的属性名总是会被强制性转为字符串类型。
Map中的常用方法有:
- set(key,value):向集合中添加新元素
- get(key):从集合中获取信息
- has(key):控制指定的键名在 Map 中是否已经存在
- delete(key):从集合中移除指定的键和对应值
- clear():移除集合中所有键值对
- size:获取集合长度
比较有意思的是:Map中的has()方法应该是采用了类似数组的of
操作符、字符串的hasOwnProperty
API的原理,它只会判断自身属性!
因为在JS中“万物皆对象”,Map 的基础也是 Object!
所以你可以看到:
let map=new Map();
map.set(1,'1');
map.set('1','1-1');
map.set('age',18);
console.log(map.size);
map.delete('age');
map.has('age');
console.log(map);
但是因为上面在对obj操作时我们做了这样的一步:obj.__proto__.age=19;
所以:
而且当我们定义了一个新变量:
这更加说明了一点:js是基于原型的,在js中相同的复杂类型一定都有一个共同的“父类”!
所以:
console.log(map.age);
这一点值得“警惕”!
Map优于普通 Object 的另一点是:在 Map 中存放的键,都是按照存入顺序排列的,而Object则会根据一套规则进行排序:
- 非负整数有限,顺序是从小到大;
- 然后是字符串、负整数、浮点数,顺序是插入的顺序;
- 最后是 Symbol,顺序是插入的顺序;
Object与Map的比较:
何时使用Map —— 存储的键不是字符串/数字/Symbol时选择Map,因为Object并不支持;要存储大量数据或需要进行许多增/删操作时选择Map,因为速度更快;需要保持插入顺序时选择Map,因为Object会改变;需要迭代/遍历时选择Map,因为它默认是可迭代对象;
何时使用Object —— 只是简单的数据结构或数据量比较小时选择Object,因为数据少时它占用内存更少,且新建效率更高;需要用到JSON进行文件传输时选择Object,因为JSON默认不支持Map;需要覆盖原型上的键时选择Object;
WeakMap
它是弱引用Map集合,也用于存储对象的弱引用。WeakMap集合中的键名必须是一个对象!
如果弱引用之外不存在其他的强引用时,引擎的垃圾回收机制会自动回收这个对象!
按照这个特性,它可以被用来“跟踪”DOM元素,这样在DOM元素消失时,可以自动销毁集合中的相关对象。
let map=new WeakMap(),
ele=document.querySelector('.ele');
map.set(ele,"ori");
let value=map.get(ele);
console.log(value); // "ori"
// 删除元素后
ele.parentNode.removeChild(ele);
ele=null;
console.log(map); // 空:Map(0) {}
除此之外,我们还可以利用它来创建一个真正的“私有属性”:
let Person=(function(){
let Data=new WeakMap();
function Person(name){
Data.set(this,{name:name});
}
Person.prototype.getName=function(){
return Data.get(this).name;
};
return Person;
})();
采用 weakMap 集合来存放私有数据。由于Person对象的实例可以直接作为集合的键使用,无须单独维护一套ID的体系来跟踪数据。只要对象实例被销毁,相关信息也被销毁,从而保证了信息的私有性。
类似es6的 class,我们通过暴露get方法完成对属性的访问。
以上是关于小酌ObjectMap和WeakMap的主要内容,如果未能解决你的问题,请参考以下文章