1.提出问题
1.什么是Map?
2.Map能做什么?
3.为什么要使用Map?
2.思考问题(11.24首次)
Map是一种新的集合类型,为这门语言带来了真正的键/值存储机制。Map的大多数特性都可以通过Object类型实现,但二者之间还是存在一些细微的差异。
一、基本API
使用new关键字和Map构造函数可以创建一个空映射
const m = new Map()
console.log(m); // Map(0) {size: 0}
console.log(typeof m); // object
创建并初识化实例,可以给Map构造函数传入一个可迭代对象,需要包含键/值对数组 可迭代对象中的每个键/值对都会按照迭代顺序插入到新映射实例中
使用map传入的键/值对都是有顺序的 这个我们先按下不表
看几个初始化实例例子
- 使用嵌套数组初始化映射
const m1 = new Map([
['key1', 'val1'],
['key2', 'val2'],
['key3', 'val3']
])
console.log(m1);
// Map(3) {'key1' => 'val1', 'key2' => 'val2', 'key3' => 'val3'}
我们发现传入的值其实是一个二维数组 而Map实例化对象后将二维数组变成了一组一组对应的key-value
- 使用自定义迭代器初始化映射
const m2 = new Map({
[Symbol.iterator]: function* () {
yield ['key1', 'val1'],
yield ['key2', 'val2'],
yield ['key3', 'val3']
}
})
console.log(m2); // Map(3) {'key1' => 'val1', 'key2' => 'val2', 'key3' => 'val3'}
也就是说实例化map对象的时候需要传入一个可迭代的数组/对象/迭代器
实例化对象说完之后 我们来看看map身上有哪些属性和方法吧
- set()方法添加键/值对
- get()方法、has()方法进行查询
- size属性获取映射中的键/值对的数量
- delete()方法、clear()方法删除键/值对
1.添加键/值对 set()
const m = new Map([])
m.set('key1','val1')
console.log(m);
// Map(1) {'key1' => 'val1'}
// set()方法返回映射实例 可以使用链式编程
m.set('key2','val2').set('key3','val3')
2.查询 get()/has()
- get()方法查找返回value值
console.log(m.get('key1')) // val1
console.log(m.get('hello')) // undefined
- has()方法查找返回布尔值
console.log(m.has('key2')) // true
console.log(m.has('hello')) // false
3.获取映射中的数量 size
console.log(m.size) // 3
4.删除映射中的键/值对 delete() / clear()
- delete()删除单个键/值对
console.log(m.delete('key1')) // true
console.log(m.delete('hello')) // false
- clear()清除所有的键/值对
m.clear()
console.log(m.size) // 0
注意点:键/值中内容或属性被修改时仍然保持不变
const m5 = new Map()
const objVal = {};
arrKey = [];
arrVal = [];
m.set(objKey, objVal)
m.set(arrKey, arrVal)
objKey.foo = 'foo'
objVal.bar = 'bar'
arrKey.push('foo')
arrVal.push('bar')
console.log(m.get(objKey)); // {bar: 'bar'}
console.log(m.get(arrKey)); // ['bar']
5.循环映射 forEach()方法
const m = new Map([
['key1', 'val1'],
['key2', 'val2'],
['key3', 'val3']
])
m.forEach((val, key) => console.log(`${key}-->${val}`))
// key1-->val1
// key2-- > val2
// key3-- > val3
6.插入顺序生成键的迭代器(按插入顺序输出key)
for (const key of m.keys()) {
console.log(key);
}
// key1
// key2
// key3
7.插入顺序生成键的迭代器(按插入顺序输出value)
for (const val of m.values()) {
console.log(val);
}
// val1
// val2
// val3
键和值在迭代器遍历时是可以修改的,但映射内部的引用则无法修改
const m1 = new Map([
['key1', 'val1']
])
for (let key of m1.keys()) {
key = 'newKey'
console.log(key); // newKey
console.log(m1.get('key1')); // val1
}
const keyObj = { id: 1 }
const m2 = new Map([
[keyObj,'val1']
])
for (let key of m2.keys()) {
key.id = 'newKey'
console.log(key); // {id: 'newKey'}
console.log(m2.get(keyObj)); // val1
}
console.log(keyObj); // {id: 'newKey'}
二、类型转换
1.Object类型转换为Map类型
var obj = { foo: "bar", baz: 42 };
var map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }
2.Map类型转换为Array类型
const m = new Map([
['key1', 'val1'],
['key2', 'val2'],
['key3', 'val3']
])
console.log([...m]); // [['key1', 'val1'],['key2', 'val2'],['key3', 'val3']]
3.Object类型转换为Array类型
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
三、Map和Object的区别
1.作为键的类型不同
Map可以使用任何JavaScript数据类型作为键
const m = new Map()
const functionKey = function () { }
const symbolKey = Symbol()
const objKey = new Object()
m.set(functionKey, 'functionValue').set(symbolKey, 'symbolValue').set(objKey, 'objValue')
alert(m.get(functionKey)) // functionValue
alert(m.get(symbolKey)) // symbolValue
alert(m.get(objKey)) // objValue
alert(m.get(function(){})) // undefined
Object只能使用数值、字符串或符号作为键
const o = new Object({
key1: 'val1',
1: 'val2',
functionKey: 'functionValue',
symbolKey: 'symbolValue',
objKey: 'objValue'
})
console.log(o);
// {1: 'val2', key1: 'val1', functionKey: 'functionValue', symbolKey: 'symbolValue', objKey: 'objValue'}
对象中不能使用引用类型作为属性值 如果非要拿引用类型来作为属性值 js会将属性值自动转换为字符串
2.插入顺序
Map实例会维护键值对的插入顺序 因此可以根据插入顺序执行迭代操作
映射实例提供了一个迭代器(Iterator)能以插入顺序生成[key,value]形式的数组 可以通过entries()方法(或者Symbol.iterator属性,它引用entries())取得这个迭代器
顺便一提 Array Object 都有Iterator迭代器 也都可以是用entries()这个方法
先来看看map实例对象使用entries()
const m = new Map([
['key1', 'val1'],
['key2', 'val2'],
['key3', 'val3']
])
for (const pair of m.entries()) {
console.log(pair);
}
// ['key1', 'val1']
// ['key2', 'val2']
// ['key3', 'val3']
map实例对象使用Symbol.iterator属性
console.log(m.entries === m[Symbol.iterator]); // true
for (const pair of m[Symbol.iterator]()) {
console.log(pair);
}
// ['key1', 'val1']
// ['key2', 'val2']
// ['key3', 'val3']
四、Object和Map应该如何选择
使用 Map:
- 储存的键不是字符串/数字/或者
Symbol时,选择Map,因为Object并不支持 - 储存大量的数据时,选择
Map,因为它占用的内存更小 - 需要进行许多新增/删除元素的操作时,选择
Map,因为速度更快 - 需要保持插入时的顺序的话,选择
Map,因为Object会改变排序 - 需要迭代/遍历的话,选择
Map,因为它默认是可迭代对象,迭代更为便捷
使用 Object:
- 只是简单的数据结构时,选择
Object,因为它在数据少的时候占用内存更少,且新建时更为高效 - 需要用到
JSON进行文件传输时,选择Object,因为JSON不默认支持Map - 需要对多个键值进行运算时,选择
Object,因为句法更为简洁 - 需要覆盖原型上的键时,选择
Object
3.回答问题
1.什么是Map?
Map是一种新的集合类型,类似于Object数据类型,但是它实现了真正的键/值对存储机制
2.Map能做什么?
- 可以存储数据
- Map 可以使用任何 JavaScript 数据类型作为键
- Map 可以确保遍历的顺序和插入的顺序一致
- Map 中判断 key 相等 主要在于
0与-0是否相等 Map中是相等的 Object中不相等的
3.为什么要使用Map?
详情请看Object和Map应该如何选择这一节内容
目前也就掌握了这一点点的知识 后期如果在项目中遇到的话 再多去思考下Map的使用场景~