再谈Object与Map的使用场景分析:性能对比分析

2023-05-07 21:25:44 浏览数 (1)

Map和Object有非常多相似的地方需要我们去更深入的了解和对比,才能分析出他们分别更适合的应用场景。

什么是Map

Map是一种数据结构(它很特别,是一种抽象的数据结构类型),数据一对对进行存储,其中包含键以及映射到该键的值。并且由于键的唯一性,因此不存在重复的键值对。

Map便是为了快速搜索和查找数据而生的

例如:{(1, "smile"), (2, "cry"), (42, "happy")}

在Map中,每一对数据的格式都为键值对的形式。

注:Map中的键和值可以是任何数据类型,不仅限于字符串或整数

什么是Object

JavaScript中的常规对象是一种字典类型的数据结构——这意味着它依然遵循与Map类型相同键值对的存储结构

Object中的key,或者我们可以称之为属性,同样是独一无二的并且对应着一个单独的value。

另外,JavaScript中的Object拥有内置原型(prototype)。需要注意的是,JavaScript中几乎所有对象都是Object实例,包括Map。

例如:{1: 'smile', 2: 'cry', 42: 'happy'}

从定义上来看,Object和Map的本质都是以键值对的方式存储数据,但实质上他们之间存在很大的区别——

  • Object遵循普通的字典规则,键必须是单一类型,并且只能是整数、字符串或是Symbol类型。但在Map中,key可以为任意数据类型(Object, Array等)。(你可以尝试将一个对象设置为一个Object的key,看看最终的数据结构)
  • 元素顺序Map会保留所有元素的顺序,而Object并不会保证属性的顺序。(如有疑问可参考:链接)
  • 继承:Map是Object的实例对象,而Object显然不可能是Map的实例对象。
代码语言:javascript复制
var map = new Map([[1,2],[3,4]]);
console.log(map instanceof Object); //true
var obj = new Object();
console.log(obj instanceof Map); //false

Object和Map的应用场景

Map相对于Object有很多优点,依然存在某些使用Object会更好的场景,毕竟Object是JavaScript中最基础的概念。

  • 如果你知道所有的key,它们都为字符串或整数(或是Symbol类型),你需要一个简单的结构去存储这些数据,Object是一个非常好的选择。构建一个Object并通过知道的特定key获取元素的性能要优于Map(字面量 vs 构造函数,直接获取 vs get()方法)
  • 如果需要在对象中保持自己独有的逻辑和属性,只能使用Object。
  • JSON直接支持Object,但尚未支持Map。因此,在某些我们必须使用JSON的情况下,应将Object视为首选。
  • Map是一个纯哈希结构,而Object不是(它拥有自己的内部逻辑)。使用delete对Object的属性进行删除操作存在很多性能问题。所以,针对于存在大量增删操作的场景,使用Map更合适
  • 不同于Object,Map会保留所有元素的顺序。Map结构是在基于可迭代的基础上构建的,所以如果考虑到元素迭代或顺序,使用Map更好,它能够确保在所有浏览器中的迭代性能
  • Map在存储大量数据的场景下表现更好,尤其是在key为未知状态,并且所有key和所有value分别为相同类型的情况下。

Map和Object性能测试

性能区别

  1. 当key为有序连续的整数时,Object的性能优于Map;(V8对Object在键为有序连续正整数时做了优化)
  2. 当key为字符串、非有序连续整数、Symbol时Map的 添加 和 读取 性能优于Object,修改 和 删除 操作性能相差不大;(Object会把键转为String类型,消耗了一部分性能)
  3. 当key为其他数据类型时,只能选择Map;(Object的键只能为string、symbol类型)

其他区别

  1. Object可以通过多种方式(字面量、new Object()、Object.create()等)创建,其中字面量的方式方便快捷。Map只能通过构造函数方式创建;
  2. Map本身具有size属性,Object需要使用 keys()、values()等方法获取;
  3. Map本身具有可迭代属性,Object不具有;
  4. Map会保持数据的插入顺序,Object不会;

具体测试代码:

代码语言:javascript复制
function createRandomKey() {
    return new Date().getTime().toString().substr(6, 7)   '-'   (Math.random() * 100000000).toString().substr(0, 7);
}
let keys = []
function setKeys() {
    for (let i = 0; i < 1000000; i  ) {
        keys.push(createRandomKey())
    }
}
setKeys()
let obj = new Object()
let map = new Map()
function getObjectTimeDiff() {
    let t1 = new Date().getTime()
    for (let i in keys) {
        obj[keys[i]] = i
    }
    let t2 = new Date().getTime()
    for (let j in keys) {
        let value = obj[keys[j]]
    }
    let t3 = new Date().getTime()
    for (let k in keys) {
        obj[keys[k]] = keys[k]
    }
    let t4 = new Date().getTime()
    for (let l in keys) {
        delete obj[keys[l]]
    }
    let t5 = new Date().getTime()
    return `object 增:${t2 - t1},读:${t3 - t2},改:${t4 - t3},删:${t5 - t4}`
}
function getMapTimeDiff() {
    let t1 = new Date().getTime()
    for (let i in keys) {
        map.set(keys[i], i)
    }
    let t2 = new Date().getTime()
    for (let j in keys) {
        let value = map.get(keys[j])
    }
    let t3 = new Date().getTime()
    for (let k in keys) {
        map.set(keys[k], keys[k])
    }
    let t4 = new Date().getTime()
    for (let l in keys) {
        map.delete(keys[l])
    }
    let t5 = new Date().getTime()
    return `map 增:${t2 - t1},读:${t3 - t2},改:${t4 - t3},删:${t5 - t4}`
}
console.log(getObjectTimeDiff())
console.log(getMapTimeDiff())

再修改代码,将keys改为下标的的集合,测试key为连续的整数时

代码语言:javascript复制
function setKeys() {
    for (let i = 0; i < 1000000; i  ) {
        keys.push(i)
    }
}

参考文章:

【译】Object与Map的异同及使用场景 https://juejin.cn/post/6844903792094232584

Map和Object性能测试https://juejin.cn/post/6992874755070099492

转载本站文章《再谈Object与Map的使用场景分析:性能对比分析》, 请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/js/2023_0418_8940.html

0 人点赞