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 相关文章推荐
Javascript下的keyCode键码值表
Apr 10 Javascript
jquery nth-child()选择器的简单应用
Jul 10 Javascript
js 自动播放的实例代码
Nov 19 Javascript
JS求平均值的小例子
Nov 29 Javascript
js实现的点击div区域外隐藏div区域
Jun 30 Javascript
javascript定义变量时带var与不带var的区别分析
Jan 12 Javascript
简单几步实现返回顶部效果
Dec 05 Javascript
websocket+node.js实现实时聊天系统问题咨询
May 17 Javascript
MvcPager分页控件 适用于Bootstrap
Jun 03 Javascript
浅析node Async异步处理模块用例分析及常用方法介绍
Nov 17 Javascript
jQuery实现的中英文切换功能示例
Jan 11 jQuery
vue设置一开始进入的页面教程
Oct 28 Javascript
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个人网站架设连环讲(一)
2006/10/09 PHP
基于PHP读取TXT文件向数据库导入海量数据的方法
2013/04/23 PHP
WordPress中获取所使用的模板的页面ID的简单方法
2015/12/31 PHP
php实现图片上传、剪切功能
2016/05/07 PHP
tp5(thinkPHP5框架)使用DB实现批量删除功能示例
2019/05/28 PHP
JavaScript fontcolor方法入门实例(按照指定的颜色来显示字符串)
2014/10/17 Javascript
js获取内联样式的方法
2015/01/27 Javascript
深入理解JavaScript系列(40):设计模式之组合模式详解
2015/03/04 Javascript
Jquery组件easyUi实现手风琴(折叠面板)示例
2016/08/23 Javascript
完美解决jQuery的hover事件在IE中不停闪动的问题
2017/02/10 Javascript
基于vue.js快速搭建图书管理平台
2017/10/29 Javascript
微信小程序结合mock.js实现后台模拟及调试
2019/03/28 Javascript
Vue路由之JWT身份认证的实现方法
2019/08/26 Javascript
小程序如何支持使用 async/await详解
2019/09/12 Javascript
webpack打包html里面img后src为“[object Module]”问题
2019/12/22 Javascript
小程序实现上传视频功能
2020/08/18 Javascript
[02:56]DOTA2矮人直升机 英雄基础教程
2013/11/26 DOTA
python 数据的清理行为实例详解
2017/07/12 Python
django用户注册、登录、注销和用户扩展的示例
2018/03/19 Python
python+opencv识别图片中的圆形
2020/03/25 Python
对python3 urllib包与http包的使用详解
2018/05/10 Python
Python3实现的爬虫爬取数据并存入mysql数据库操作示例
2018/06/06 Python
Tensorflow中使用tfrecord方式读取数据的方法
2018/06/19 Python
TensorFlow实现Logistic回归
2018/09/07 Python
python 实现交换两个列表元素的位置示例
2019/06/26 Python
python 利用浏览器 Cookie 模拟登录的用户访问知乎的方法
2019/07/11 Python
Python3 搭建Qt5 环境的方法示例
2020/07/16 Python
html5 跨文档消息传输示例探讨
2013/04/01 HTML / CSS
在家更换处方镜片:Lensabl
2019/05/01 全球购物
牧马人澳大利亚官网:Wrangler澳大利亚
2019/10/08 全球购物
介绍一下如何利用路径遍历进行攻击及如何防范
2014/01/19 面试题
销售总监岗位职责
2014/01/04 职场文书
毕业生自荐书模版
2014/01/04 职场文书
拉拉队口号
2014/06/16 职场文书
校运会加油稿大全
2015/07/22 职场文书
Golang: 内建容器的用法
2021/05/05 Golang