Map和Object性能测试

2,792 阅读3分钟

这是我参与8月更文挑战的第2天,活动详情查看: 8月更文挑战

背景

今天看到一道力扣题时发现频繁操作键值对时使用Map比Object性能更优,于是简单测试了一下两者的区别。


结论

先上结论:

性能区别

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

其他区别

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

过程

看完了结论再来看看测试的过程, 先测试key为String时两者的区别

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())

我们多次执行会得到大概如下的数据(会因执行环境不同得到不同数据),可以明显看出Map在新增键值、读取键值时耗时低于Object

第一次执行
object 增:1121,读:710,改:339,删:397
map 增:545,读:220,改:453,删:491

第二次执行
object 增:1145,读:702,改:330,删:396
map 增:542,读:241,改:468,删:510

第三次执行
object 增:1153,读:707,改:359,删:403
map 增:546,读:237,改:465,删:507

第四次执行
object 增:1138,读:697,改:333,删:387
map 增:542,读:248,改:451,删:444
...

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

function setKeys() {
    for (let i = 0; i < 1000000; i++) {
        keys.push(i)
    }
}

多次执行

第一次执行
object 增:256,读:140,改:134,删:234
map 增:419,读:192,改:294,删:432

第二次执行
object 增:234,读:137,改:136,删:232
map 增:412,读:186,改:283,删:425

第三次执行
object 增:254,读:139,改:130,删:227
map 增:411,读:181,改:296,删:430

第四次执行
object 增:262,读:140,改:135,删:241
map 增:421,读:205,改:309,删:459
...

可以看到,在连续整数作为key时,Object的性能优于Map