再谈Object与Map的使用场景分析:性能对比分析
Author:zhoulujun Date:
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的实例对象。
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性能测试
性能区别
当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不会;
具体测试代码:
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为连续的整数时
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