es6提供了一个Map类,这是新增的一个数据结构,用起来有点像Object,这二者到底有什么区别呢?
Object本质上是哈希结构的键值对的集合,它只能用字符串、数字或者Symbol等简单数据类型当作键,这就带来了很大的限制。
比如以下这个例子,我想将dom节点作为键,但是由于对象只接受字符串作为键名,所以键被自动转为字符串[object HTMLDivElement],这显然不是我们想要的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Map</title>
</head>
<body>
<div id="cont">
</div>
</body>
</html>
<script>
let cont = document.getElementById('cont')
let obj = {}
obj[cont] = 'hello,world'
console.log(obj)//[object HTMLDivElement]: "hello,world"
</script>
Map类继承了Object,并对Object功能做了一些拓展,Map的键可以是任意的数据类型。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Map</title>
</head>
<body>
<div id="cont">
</div>
</body>
</html>
<script>
let cont = document.getElementById('cont')
let m = new Map()
m.set(cont, 'hello,world')
console.log(m)
console.log(m.get(cont))
</script>
二者的区别主要有以下几点:
同名碰撞
我们知道,对象其实就是在堆开辟了一块内存,其实Map的键存的就是这块内存的地址。只要地址不一样,就是两个不同的键,这就解决了同名属性的碰撞问题,而传统的Object显然做不到这一点。
let m = new Map()
m.set({},1)
m.set({},2)
m.set({},3) //每一次都是开辟新的堆内存作为键
console.log(m) //Map { {} => 1, {} => 2, {} => 3 }
let o = {}
o['a'] = 1
o['a'] = 2
o['a'] = 3
console.log(o) //{ a: 3 }
可迭代
new Map([iterable])
Map实现了迭代器,可用for...of遍历,而Object不行。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Map</title>
</head>
<body>
<div id="cont">
</div>
</body>
</html>
<script>
let cont = document.getElementById('cont')
let m = new Map()
m.set(cont, 'hello,world')//dom对象作为键
m.set(['username'],'jack')//数组作为键
m.set(true,1)//boolean类型作为键
//可以迭代
for(let val of m){
console.log(val[0])//key
console.log(val[1])//value
}
</script>
长度
Map可以直接拿到长度,而Object不行。
let m = new Map()
m.set({a:1}, 'hello,world')//dom对象作为键
m.set(['username'],'jack')//数组作为键
m.set(true,1)//boolean类型作为键
console.log(m.size)//3
有序性
填入Map的元素,会保持原有的顺序,而Object无法做到。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Map</title>
</head>
<body>
<div id="cont">
</div>
</body>
</html>
<script>
let cont = document.getElementById('cont')
let m = new Map()
m.set(cont, 'hello,world')//dom对象作为键
m.set(['username'],'jack')//数组作为键
m.set(true,1)//boolean类型作为键
//可以保持原有顺序打印
for(let [key,value] of m){
console.log(key)
}
let obj = new Object()
obj['jack'] = 1
obj[0] = 2
obj[5] = 3
obj['tom'] = 4
//填入Object的元素key是自动按照字符串排序的,数字排在前面
for(let k in obj){
console.log(k) // 0 5 jack tom
}
</script>
可展开
Map可以使用省略号语法展开,而Object不行。
let m = new Map()
m.set({a:1}, 'hello,world')//dom对象作为键
m.set(['username'],'jack')//数组作为键
m.set(true,1)//boolean类型作为键
console.log([...m])//可以展开为二维数组
let obj = new Object()
obj['jack'] = 1
obj[0] = 2
obj[5] = 3
obj['tom'] = 4
console.log([...obj])//TypeError: obj is not iterable