IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> js中object,map和weakMap的简析和区别 -> 正文阅读

[JavaScript知识库]js中object,map和weakMap的简析和区别

请添加图片描述

Map

Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值) 都可以作为一个键或一个值。

Object和map的比较

ObjectsMaps 类似的是,它们都允许你按键存取一个值、删除键、检测一个键是否绑定了值。因此(并且也没有其他内建的替代方式了)过去我们一直都把对象当成 Maps 使用。不过 MapsObjects 有一些重要的区别,在下列情况里使用 Map 会是更好的选择

  1. 一个 Map的键可以是任意值,包括函数、对象或任意基本类型。而一个Object 的键必须是一个 String 或是Symbol

    如下示例代码,我们使用一个方法作为键值再判断输出,我们可以看到object中如果使用方法作为键值,会将方法体转化为字符串当做键值,而map则是直接引用了方法作为键值

    const obj = {}
    const func = ()=>{}
    obj[func] = "funcValue"
    ?
    const map = new Map()
    map.set(func,"funcValue")
    ?
    console.log(obj)// { '()=>{}': 'funcValue' }
    ?
    console.log(map)// Map(1) { [Function: func] => 'funcValue' }
    ?
    
  2. Map 中的 key 是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值,Map 的键值对个数可以轻易地通过size属性获取,Map 是可迭代的(iterable)的。而 Object 的键是无序的,Object 的键值对个数只能手动计算,迭代一个Object需要以某种方式获取它的键然后才能迭代。

    这就意味着map拥有着类似数组的属性,而且Map对象可以直接使用数组原型的一些方法例如 for…of… ,foreach等等`

    const obj = {}
    const func = ()=>{}
    obj[func] = "funcValue"
    ?
    const map = new Map()
    map.set(func,"funcValue")
    ?
    console.log(obj.forEach((item)=>{
      console.log(item) // obj.forEach is not a function
    }))
    ?
    ?
    map.forEach((item)=>{
      console.log(item) // funcValue
    })
    ?
    

深入分析

从上面的例子中我们可以看到,Map对象其实是像ArrayObject的合并版,那么我们就根据Web MDN中用的几个例子深入了解一下Map对象

  1. 合并操作

    Map对象可以与数组或者对象进行合并,如下例

    const map = new Map()
    map.set('a',"这里是a")
    const obj = {b:'这里是b'}
    const arr = ['c','这里是c']
    ?
    ?
    const mergeArrMap = new Map([...map,arr])
    console.log(mergeArrMap) // Map(2) { 'a' => '这里是a', 'c' => '这里是c' }
    console.log(mergeArrMap.size) // 2
    ?
    Object.assign(map,obj)
    console.log(map) // Map(1) { 'a' => '这里是a', b: '这里是b' }
    console.log(map.size) // 1
    

    上面的例子可以看到为Map设置对象属性也是可以的,但是可能引起大量的混乱。在调用api的时候返回与我们预期不符的结果。

    所以我们最好还是使用map的api进行操作,例如:

    const map = new Map()
    map.set(key,value)
    map.delete(key)
    

js中的map对于学过php同学来说是非常类似php中的对象数组的,个人理解Map对象就是一个二维数组,内层数组只取前两个值,第一个值是外层数组的键,第二个值是外层数组的值,因此 Map对象 具有类似数组和对象功能和api

const arr = [
  ['a','我是a啊'],
  ['b','我是b啊'],
  ['c','我是c啊','笑死,爷还有一个值'],
  ['赵四','我是赵四啊']
]
const map = new Map(arr)
console.log(map) // Map(3) { 'a' => '我是a啊', 'b' => '我是b啊', '赵四' => '我是赵四啊' }
  1. 性能

    根据MDN所说在Map对象频繁增删键值对的场景下表现更好。我们写一个简单的例子测试一下

    const obj = {}
    ?
    console.time()
    for(let i =0 ;i<=1000000;i++){
      obj[i] = '我是对象的值'+i
    }
    for(let i =1000000 ;i>0;i--){
      delete obj[i]
    }
    console.timeEnd() //322.576ms
    ?
    const map = new Map()
    console.time()
    for(let i =0 ;i<=1000000;i++){
      map.set(i,'我是map的值'+i)  
    }
    for(let i =1000000 ;i>0;i--){
      map.delete(i)  
    }
    console.timeEnd() //390.84ms
    

    不知道是不是使用场景不对,测试了几次都是原始object的增删速度比较快,如果有了解合适场景的小伙伴欢迎补充

WeakMap

WeakMap 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。

Object和map的比较

在 JavaScript 里,map API 可以通过使其四个 API 方法共用两个数组(一个存放键,一个存放值)来实现。给这种 map 设置值时会同时将键和值添加到这两个数组的末尾。从而使得键和值的索引在两个数组中相对应。当从该 map 取值的时候,需要遍历所有的键,然后使用索引从存储值的数组中检索出相应的值。

但这样的实现会有两个很大的缺点,首先赋值和搜索操作都是 O(n) 的时间复杂度( n 是键值对的个数),因为这两个操作都需要遍历全部整个数组来进行匹配。另外一个缺点是可能会导致内存泄漏,因为数组会一直引用着每个键和值。这种引用使得垃圾回收算法不能回收处理他们,即使没有其他任何引用存在了。

相比之下,原生的 WeakMap 持有的是每个键对象的“弱引用”,这意味着在没有其他引用存在时垃圾回收能正确进行。原生 WeakMap 的结构是特殊且有效的,其用于映射的 key 只有在其没有被回收时才是有效的。

1.一个 Map的键可以是任意值,包括函数、对象或任意基本类型。而weakMap其键必须是对象,而值可以是任意的。一下为weakMap的使用方式

const map = new WeakMap()
let obj = {'赵四':'我是赵四'}
?
map.set(obj,'我还是赵四')
?
?
console.log(map.get(obj)) // 我还是赵四

在vue3.x版本源码中就用到了weakMap作为响应方法的一个存储方式,这样做的一个好处是可以防止内存泄露,如MDN所说如果你要往对象上添加数据,又不想干扰垃圾回收机制,就可以使用 WeakMap

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-03 17:00:20  更:2021-10-03 17:01:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 21:37:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码