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 相关文章推荐
Script的加载方法小结
Jan 12 Javascript
javascript基础之查找元素的详细介绍(访问节点)
Jul 05 Javascript
js操作table示例(个人心得)
Nov 29 Javascript
javascript运行机制之this详细介绍
Feb 07 Javascript
js友好的时间返回函数
Aug 24 Javascript
Vue.JS入门教程之处理表单
Dec 01 Javascript
jquery 验证用户名是否重复代码实例
May 14 jQuery
微信小程序实现文件、图片上传功能
Aug 18 Javascript
Vue 实现前端权限控制的示例代码
Jul 09 Javascript
nest.js 使用express需要提供多个静态目录的操作方法
Oct 24 Javascript
windows实现npm和cnpm安装步骤
Oct 24 Javascript
vue3.0 加载json的方法(非ajax)
Oct 26 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
yii框架配置默认controller和action示例
2014/04/30 PHP
php实现文件管理与基础功能操作
2017/03/21 PHP
JavaScript 学习笔记一些小技巧
2010/03/28 Javascript
js隐藏与显示回到顶部按钮及window.onscroll事件应用
2013/01/25 Javascript
jsp网页搜索结果中实现选中一行使其高亮
2014/02/17 Javascript
javascript中字体浮动效果的简单实例演示
2015/11/18 Javascript
简单实现JS对dom操作封装
2015/12/02 Javascript
js原型链与继承解析(初体验)
2016/05/09 Javascript
JS实现表单多文件上传样式美化支持选中文件后删除相关项
2016/09/30 Javascript
js学习之----深入理解闭包
2016/11/21 Javascript
react性能优化达到最大化的方法 immutable.js使用的必要性
2017/03/09 Javascript
微信小程序封装http访问网络库实例代码
2017/05/24 Javascript
详解vuejs之v-for列表渲染
2017/06/22 Javascript
详解使用webpack打包编写一个vue-toast插件
2017/11/08 Javascript
浅谈ECMAScript 中的Array类型
2019/06/10 Javascript
JS中的算法与数据结构之常见排序(Sort)算法详解
2019/08/16 Javascript
Python3基础之基本数据类型概述
2014/08/13 Python
Python错误: SyntaxError: Non-ASCII character解决办法
2017/06/08 Python
Python通过命令开启http.server服务器的方法
2017/11/04 Python
python使用os.listdir和os.walk获得文件的路径的方法
2017/12/16 Python
Python实现的井字棋(Tic Tac Toe)游戏示例
2018/01/31 Python
python学生信息管理系统
2018/03/13 Python
python微信公众号之关键词自动回复
2018/06/15 Python
对python 自定义协议的方法详解
2019/02/13 Python
tensorflow之变量初始化(tf.Variable)使用详解
2020/02/06 Python
opencv python在视屏上截图功能的实现
2020/03/05 Python
安装并免费使用Pycharm专业版(学生/教师)
2020/09/24 Python
css3实现椭圆轨迹旋转的示例代码
2018/10/29 HTML / CSS
英国最大的纸工艺品商店:CraftStash
2018/12/01 全球购物
时尚孕妇装:HATCH Collection
2019/09/24 全球购物
Oral-B荷兰:牙医最推荐的品牌
2020/02/25 全球购物
宣传策划类求职信范文
2014/01/31 职场文书
决心书标准格式
2014/03/11 职场文书
陶瓷类经典广告语集锦
2019/10/25 职场文书
浅谈node.js中间件有哪些类型
2021/04/29 Javascript
SQLServer RANK() 排名函数的使用
2022/03/23 SQL Server