JavaScript中Object、map、weakmap的区别分析


Posted in Javascript onDecember 15, 2020

前言

ECMAScript 6以前,在JavaScript中实现“键/值”式存储可以使用Object来方便高效地完成,也就是使用对象属性作为键,再使用属性来引用值。但这种实现并非没有问题,为此TC39委员会专门为“键/值”存储定义了一个规范。作为ECMAScript 6的新增特性,Map是一种新的集合类型,为这门语言带来了真正的键/值存储机制。Map的大多数特性都可以通过Object类型实现,但二者之间还是存在一些细微的差异。具体实践中使用哪一个,还是值得细细甄别。

一、map 的使用

初始化

object 可以使用字面量、构造函数、Object.crate的形式创建。而map 只能通过new 关键字和构造函数创建。对于map如果想在创建的同时初始化实例,可以给Map构造函数传入一个可迭代对象,需要包含键/值对数组。可迭代对象中的每个键/值对都会按照迭代顺序插入到新映射实例中:

object 的创建方式
 
const object = {}
const object1 = new Object()
const object2 = Object.create({})
 
map 的创建方式
//使用new关键字
const m0 = new Map;
// 使用嵌套数组初始化映射
const m1 = new Map([
 ["key1", "val1"],
 ["key2", "val2"],
 ["key3", "val3"]
]);
alert(m1.size); // 3
// 使用自定义迭代器初始化映射
const m2 = new Map({
[Symbol.iterator]: function*() {
 yield ["key1", "val1"];
 yield ["key2", "val2"];
 yield ["key3", "val3"];
}
});
alert(m2.size); // 3
// 映射期待的键/值对,无论是否提供
const m3 = new Map([[]]);
alert(m3.has(undefined)); // true
alert(m3.get(undefined)); // undefined

map键类型

与Object只能使用数值、字符串或符号作为键不同,Map可以使用任何JavaScript数据类型作为键。Map内部使用SameValueZero比较操作(ECMAScript规范内部定义,语言中不能使用),基本上相当于使用严格对象相等的标准来检查键的匹配性。与Object类似,映射的值是没有限制的。

const m = new Map();
 const functionKey = function() {};
 const symbolKey = Symbol();
 const objectKey = new Object();
 m.set(functionKey, "functionValue");
 m.set(symbolKey, "symbolValue");
 m.set(objectKey, "objectValue");
 alert(m.get(functionKey)); // functionValue
 alert(m.get(symbolKey)); // symbolValue
 alert(m.get(objectKey)); // objectValue
 // SameValueZero比较意味着独立实例不冲突
 alert(m.get(function() {})); // undefined

顺序与迭代

与Object类型的一个主要差异是,Map实例会维护键值对的插入顺序,因此可以根据插入顺序执行迭代操作。映射实例可以提供一个迭代器(Iterator),能以插入顺序生成[key,value]形式的数组。可以通过entries()方法(或者Symbol.iterator属性,它引用entries())取得这个迭代器:

const m = new Map([
 ["key1", "val1"],
 ["key2", "val2"],
 ["key3", "val3"]
]);
alert(m.entries === m[Symbol.iterator]); // true
for (let pair of m.entries()) {
 alert(pair);
}
// [key1,val1]
// [key2,val2]
// [key3,val3]
for (let pair of m[Symbol.iterator]()) {
 alert(pair);
}
// [key1,val1]
// [key2,val2]
// [key3,val3]

二、选择Object还是Map

对于多数Web开发任务来说,选择Object还是Map只是个人偏好问题,影响不 大。不过,对于在乎内存和性能的开发者来说,对象和映射之间确实存在显著的 差别。

1.内存占用

Object和Map的工程级实现在不同浏览器间存在明显差异,但存储单个键/值对所占用的内存数量都会随键的数量线性增加。批量添加或删除键/值对则取决于各浏览器对该类型内存分配的工程实现。不同浏览器的情况不同,但给定固定大小的内存,Map大约可以比Object多存储50%的键/值对。

2.插入性能

向Object和Map中插入新键/值对的消耗大致相当,不过插入Map在所有浏览器中一般会稍微快一点儿。对这两个类型来说,插入速度并不会随着键/值对数量而线性增加。如果代码涉及大量插入操作,那么显然Map的性能更佳。

3.查找速度

与插入不同,从大型Object和Map中查找键/值对的性能差异极小,但如果只包含少量键/值对,则Object有时候速度更快。在把Object当成数组使用的情况下(比如使用连续整数作为属性),浏览器引擎可以进行优化,在内存中使用更高效的布局。这对Map来说是不可能的。对这两个类型而言,查找速度不会随着键/值对数量增加而线性增加。如果代码涉及大量查找操作,那么某些情况下可能选择Object更好一些。

4.删除性能

使用delete删除Object属性的性能一直以来饱受诟病,目前在很多浏览器中仍然如此。为此,出现了一些伪删除对象属性的操作,包括把属性值设置为undefined或null。但很多时候,这都是一种讨厌的或不适宜的折中。而对大多数浏览器引擎来说,Map的delete()操作都比插入和查找更快。如果代码涉及大量删除操作,那么毫无疑问应该选择Map

三、weakMap

ECMAScript 6新增的“弱映射”(WeakMap)是一种新的集合类型,为这门语言带来了增强的键/值对存储机制。WeakMap是Map的“兄弟”类型,其API也是Map的子集。WeakMap中的“weak”(弱),描述的是JavaScript垃圾回收程序对待“弱映射”中键的方式。

weakcMap 的弱
WeakMap中“weak”表示弱映射的键是“弱弱地拿着”的。意思就是,这些键不属于正式的引用,不会阻止垃圾回收,当浏览器需要回收内存时这些键是可能会被回收的。但要注意的是,弱映射中值的引用可不是“弱弱地拿着”的。只要键存在,键/值对就会存在于映射中,并被当作对值的引用,因此就不会被当作垃圾回收。

//会被回收
const wm = new WeakMap();
wm.set({}, "val");

//不会被回收
const wm2 = new WeakMap();
const container = {
 key: {}
};
wm2.set(container.key, "val");
function removeReference() {
 container.key = null;
}

在vm中,set()方法初始化了一个新对象并将它用作一个字符串的键。因为没有指向这个对象的其他引用,所以当这行代码执行完成后,这个对象键就会被当作垃圾回收。然后,这个键/值对就从弱映射中消失了,使其成为一个空映射。在这个例子中,因为值也没有被引用,所以这对键/值被破坏以后,值本身也会成为垃圾回收的目标。
而在vm1中,container对象维护着一个对弱映射键的引用,因此这个对象键不会成为垃圾回收的目标。不过,如果调用了removeReference(),就会摧毁键对象的最后一个引用,垃圾回收程序就可以把这个键/值对清理掉。

weakMap使用
WeakMap的初始化与map并没有什么太大的差别,需要注意的是weakMap只能使用object类型的键,这与weakMap的作用是息息相关的

const key1 = {id: 1},
 key2 = {id: 2},
 key3 = {id: 3};
// 使用嵌套数组初始化弱映射
const wm1 = new WeakMap([
 [key1, "val1"],
 [key2, "val2"],
 [key3, "val3"]
]);
alert(wm.get(key1)); // val1
alert(wm.get(key2)); // val2
alert(wm.get(key3)); // val3

// 原始值可以先包装成对象再用作键
const stringKey = new String("key1");
const wm3 = new WeakMap([
 stringKey, "val1"
]);
alert(wm3.get(stringKey)); // "val1"

四、使用weakMap的场景

WeakMap实例与现有JavaScript对象有着很大不同,可能一时不容易说清楚应该怎么使用它。这个问题没有唯一的答案,但已经出现了很多相关策略。

DOM节点元数据
因为WeakMap实例不会妨碍垃圾回收,所以非常适合保存关联元数据。如以下代码所示,下面的例子使用的是WeakMap,当节点从DOM树中被删除后,垃圾回收程序就可以立即释放其内存(假设没有其他地方引用这个对象):

const wm = new WeakMap();
const loginButton = document.querySelector('#login');
// 给这个节点关联一些元数据
wm.set(loginButton, {disabled: true});

总结

以上就是object、map、weakmap的相关使用和区别了。其实在大多数情况下,object和map使用是没有什么区别的,但是如果你需要大量的插入和查找删除,或者需要使用对象作为键值的话,使用map是比较优的选择。另外weakMap在使用的对象可能会被动态删除的情况下,比map具有优化内存的优势。

以上就是JavaScript中Object、map、weakmap的区别分析的详细内容,更多关于JavaScript中Object、map、weakmap区别的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
js常用函数 不错
Sep 08 Javascript
jQuery基础框架浅入剖析
Dec 27 Javascript
JS 实现获取打开一个界面中输入的值
Mar 19 Javascript
代码获取历史上的今天发生的事
Apr 11 Javascript
js实现获取当前时间是本月第几周的方法
Aug 11 Javascript
JS实现的另类手风琴效果网页内容切换代码
Sep 08 Javascript
Javascript oop设计模式 面向对象编程简单实例介绍
Dec 13 Javascript
easyUI combobox实现联动效果
Jan 17 Javascript
layui分页效果实现代码
May 19 Javascript
Vue.js 十五分钟入门图文教程
Sep 12 Javascript
动态内存分配导致影响Javascript性能的问题
Dec 18 Javascript
jQuery实现简易聊天框
Feb 08 jQuery
JavaScript中遍历的十种方法总结
Dec 15 #Javascript
token 机制和实现方式
Dec 15 #Javascript
vue从后台渲染文章列表以及根据id跳转文章详情详解
Dec 14 #Vue.js
一分钟学会JavaScript中的try-catch
Dec 14 #Javascript
Vue在H5 项目中使用融云进行实时个人单聊通讯
Dec 14 #Vue.js
vue的hash值原理也是table切换实例代码
Dec 14 #Vue.js
element-ui点击查看大图的方法示例
Dec 14 #Javascript
You might like
php后台多用户权限组思路与实现程序代码分享
2012/02/13 PHP
php实现有趣的人品测试程序实例
2015/06/08 PHP
php中 $$str 中 "$$" 的详解
2015/07/06 PHP
部署PHP时的4个配置修改说明
2015/10/19 PHP
document对象execCommand的command参数介绍
2006/08/01 Javascript
Firefox下无法正常显示年份的解决方法
2014/09/04 Javascript
JavaScript中的类与实例实现方法
2015/01/23 Javascript
JavaScript中字符串分割函数split用法实例
2015/04/07 Javascript
jQuery插件boxScroll实现图片轮播特效
2015/07/14 Javascript
jQuery实现自定义右键菜单的树状菜单效果
2015/09/02 Javascript
实例讲解JavaScript中instanceof运算符的用法
2016/06/08 Javascript
jquery实现网页定位导航
2016/08/23 Javascript
常用的js方法合集
2017/03/10 Javascript
浅谈react 同构之样式直出
2017/11/07 Javascript
axios post提交formdata的实例
2018/03/16 Javascript
JavaScript闭包原理与用法实例分析
2018/08/10 Javascript
Vue 引入AMap高德地图的实现代码
2019/04/29 Javascript
python和C语言混合编程实例
2014/06/04 Python
在Python的Django框架中获取单个对象数据的简单方法
2015/07/17 Python
Python爬取十篇新闻统计TF-IDF
2018/01/03 Python
Python线程同步的实现代码
2018/10/03 Python
django框架防止XSS注入的方法分析
2019/06/21 Python
python计算二维矩形IOU实例
2020/01/18 Python
解决Pycharm 导入其他文件夹源码的2种方法
2020/02/12 Python
Python: glob匹配文件的操作
2020/12/11 Python
CSS3 text-shadow实现文字阴影效果
2016/02/24 HTML / CSS
详解HTML5中垂直上下居中的解决方案
2017/12/20 HTML / CSS
国际经济贸易专业推荐信
2013/11/06 职场文书
安全教育演讲稿
2014/05/09 职场文书
2014年医药代表工作总结
2014/11/22 职场文书
出国签证在职证明范本
2014/11/24 职场文书
2015年小学中秋节活动总结
2015/03/23 职场文书
Pytest中skip skipif跳过用例详解
2021/06/30 Python
php 文件上传至OSS及删除远程阿里云OSS文件
2021/07/04 PHP
vue的项目如何打包上线
2022/04/13 Vue.js
python解析json数据
2022/04/29 Python