Map对象 兼容性ES6 Edge12
Map
对象保存键值对,并且能够记住键的原始插入顺序。
任何值(对象或者原始值) 都可以作为一个键或一个值。
一个Map对象在迭代时会根据对象中元素的插入顺序来进行 — 一个 for...of
循环在每次迭代后会返回一个形式为[key,value]的数组。所以说一定要知道顺序,这样在进行for...of迭代时,得到数组值的顺序就可以确定了。Set对象同理。
[[key,value], [key,value], [key,value]]
Objects
和 Maps
类似的是,它们都允许你按键存取一个值、删除键、检测一个键是否绑定了值
Maps
和 Objects
有一些重要的区别,在下列情况里使用 Map
会是更好的选择:
Map | Object |
意外的键 | Map 默认情况不包含任何键。只包含显式插入的键。 | 一个 注意: 虽然 ES5 开始可以用 |
---|---|---|
键的类型 | 一个 Map 的键可以是任意值,包括函数、对象或任意基本类型。 | 一个Object 的键必须是一个 String 或是Symbol 。 |
键的顺序 |
| 一个 注意:自ECMAScript 2015规范以来,对象确实保留了字符串和Symbol键的创建顺序; 因此,在只有字符串键的对象上进行迭代将按插入顺序产生键。 |
Size | Map 的键值对个数可以轻易地通过size 属性获取 | Object 的键值对个数只能手动计算 |
迭代 | Map 是 iterable 的,所以可以直接被迭代。 | 迭代一个Object 需要以某种方式获取它的键然后才能迭代。 |
性能 | 在频繁增删键值对的场景下表现更好。 | 在频繁添加和删除键值对的场景下未作出优化。 |
键的相等
NaN
是与 NaN
相等的(虽然 NaN !== NaN
),剩下所有其它的值是根据 ===
运算符的结果判断是否相等。
ECMAScript规范中,-0
和+0
被认为是相等的,尽管这在早期的草案中并不是这样
引用值判断索引是否相等,原始值判断值是否相等
new Map()设置属性及值
(1)接受一个数组,数组中的每项都是由key值和value值组成的数组——(二维数组)
let key1 = "a", key2 = "b", key3 = "c";
let value1 = 1, value2 = 2, value3 = 3;
let map = new Map([
[key1,value1],
[key2,value2],
[key3,value3]
])
Map(3) {"a" => 1, "b" => 2, "c" => 3}
(2)接受一个迭代对象(iterable对象)组成,其元素为键值对(两个元素的数组) 每个键值对都会添加到新的 Map。null
会被当做 undefined。
let key1 = "a", key2 = "b", key3 = "c";
let value1 = 1, value2 = 2, value3 = 3;
let map = new Map([
[key1,value1],
[key2,value2],
[key3,value3]
])
接受一个Map对象
console.log(new Map(map)); Map(3) {"a" => 1, "b" => 2, "c" => 3}
接受一个Map对象的entries()执行结果
console.log(new Map(map.entries())); Map(3) {"a" => 1, "b" => 2, "c" => 3}
let iterable = {};
iterable[Symbol.iterator] = function* () {
yield ["a1",1];
yield ["b1",2];
yield ["c1",3];
}
接受一个生成器的iterable对象
console.log(new Map(iterable)) Map(3) {"a1" => 1, "b1" => 2, "c1" => 3}
克隆Map对象
以下克隆Map对象的方式,可以深度克隆。注意看以下代码中的注释
引用值的=赋值,是将地址直接赋值,所以操作其中一个,会影响另一个引用值。但是其他对引用值的操作,是开辟新的空间地址,两者一般不受影响。
let arr = [1,2,3];
let arr1 = [4,5,6];
let keyObj = {};
let original = new Map([
[1, arr1],
[keyObj,"abc"],
[arr,arr1]
]);
let clone = new Map(original);
// new Map的方式进行克隆,实际上就是在代码中再写一个Map对象
clone = new Map([
[1, arr1],
[keyObj,"abc"],
[arr,arr1]
]);
// 不管是新设置还是修改或者删除,都是对Map对象的操作
// 对original Map对象的操作,不影响clone Map对象
original.set(2,'two');
original.set(1,"1");
original.set(keyObj,"xyz");
// 修改后的original Map对象
original = new Map([
[1, "1"],
[keyObj,"xyz"],
[arr,arr1],
[2,'two']
]);
// 但是对变量的修改,会影响到该变量所在的Map对象
arr1.push(7);
console.log(original.get(keyObj),clone.get(keyObj)); //xyz abc
console.log(original.get(arr),clone.get(arr)); //[4, 5, 6, 7] [4, 5, 6, 7]
console.log(original === clone); //false. 不为同一个对象的引用
相关属性
1、Map.prototype Map对象原型
Map
实例继承自Map.prototype
。你可以使用这个构造函数的原型对象来给所有的Map实例添加属性或者方法。
2、size属性 Map.prototype.size
与Set方法的size属性一样:size 属性的值是一个整数,表示 Map 对象有多少个键值对。size 是只读属性,用set 方法修改size返回 undefined,即不能改变它的值。
3、Map.prototype.constructor Map的构造函数
返回一个函数,它创建了实例的原型。默认是Map
函数。
相关方法
1、set方法
(1)set()
方法为 Map
对象添加或更新一个指定了键(key
)和值(value
)的(新)键值对。
(2)因为 Set() 方法返回 Map 对象本身,所以你可以像下面这样链式调用它。
(3)键可以是一个值,也可以是一个变量
let myMap = new Map();
myMap.set("a", 1).set("b", 2).set("c",3);
console.log(myMap); //Map(3) {"a" => 1, "b" => 2, "c" => 3}
2、get方法
返回一个 Map
对象中与指定键相关联的值,如果找不到这个键则返回 undefined
。
let myMap = new Map();
myMap.set("a", 1).set("b", 2).set("c",3);
console.log(myMap.get("a")); //1
3、forEach方法
forEach
仅仅是对 Map
对象中的每一个元素执行一遍 callback
函数,它不会返回任何值。
回调函数接收三个参数:value key map 即每次回调执行的value值、key值、Map副本对象。
我需要熟悉一个词:数组中的item index 与 此处的value key。item index 与value key其实是对应的。
let myMap = new Map();
myMap.set("a", 1).set("b", 2).set("c",3);
myMap.forEach((value, key, thisArg) => {
console.log(thisArg); //Map(3) {"a" => 1, "b" => 2, "c" => 3}
})
4、keys方法
keys()
返回一个存在引用关系的 MapIterator对象,该对象的[[Entries]]属性是由key键值组成的Iterator对象。
let myMap = new Map();
myMap.set("name", "zhuzhu")
.set(23, 24)
.set(false, true)
.set(["1",2], ["js","html","css"])
.set({}, {a:1,b:2});
console.log(myMap.keys())
5、values方法
返回一个MapIterator对象,该对象的[[Entries]]属性是一个由value值组成的Iterator对象。
let myMap = new Map();
myMap.set("name", "zhuzhu")
.set(23, 24)
.set(false, true)
.set(["1",2], ["js","html","css"])
.set({}, {a:1,b:2});
let valuesMap = myMap.values()
console.log(valuesMap)
valuesMap.next()
console.log(valuesMap.next())
6、entries方法(Map对象的[Symbol.iterator]属性也指向该方法)
返回一个MapIterator对象,该对象的中的[[Entries]]属性,是由每项{key:key值,value:value值}的对象,组成的Iterator对象。
MapIterator对象可以调用next方法
let myMap = new Map();
myMap.set("name", "zhuzhu")
.set(23, 24)
.set(false, true)
.set(["1",2], ["js","html","css"])
.set({}, {a:1,b:2});
let entriesMap = myMap.entries();
console.log(entriesMap)
console.log(entriesMap.next())
调用next方法的结果:value属性是一个数组,0项是对应的key,1项是对应的value值
7、has方法
方法has()
返回一个Boolean 值,用来表明map 中是否存在指定元素。
key 必填. 用来检测是否存在指定元素的键值.
let myMap = new Map();
myMap.set("name", "zhuzhu")
.set(23, 24)
.set(false, true)
.set(["1",2], ["js","html","css"])
.set({}, {a:1,b:2});
console.log(myMap.has(["1",2])); false
console.log(myMap.has(23)); true
上面代码中 引用属性是要找同一个地址的,原始值可以找到该属性。
8、delete方法
delete()
方法用于移除 Map
对象中指定的元素。
key 必填。从 Map
对象中移除的元素的键。
如果 Map
对象中存在该元素,则移除它并返回 true
;否则如果该元素不存在则返回 false
。
9、clear方法
clear()
方法会移除Map对象中的所有元素。清空Map对象。
var myMap = new Map();
myMap.set("bar", "baz");
myMap.set(1, "foo");
myMap.size; // 2
myMap.has("bar"); // true
myMap.clear();
myMap.size; // 0
myMap.has("bar") // false
注意的事项
1、关于键值
NaN
是与 NaN
相等的(虽然 NaN !== NaN 且 NaN != NaN
),剩下所有其它的值是根据 ===
运算符的结果判断是否相等。
(1)NaN作为键值
myMap.set(NaN, "aaa");
console.log(myMap.get(NaN)); aaa
console.log(myMap.get(Number("abc"))); aaa
上面代码中值为NaN的键,其对应的value都是aaa。
(2)undefined作为键值
let key;
myMap.set(undefined, "aaa");
console.log(myMap.get(undefined)); aaa
console.log(myMap.get(key)); aaa
上面代码中值为undefined的键,其对应的value都是aaa。
(3) null作为键值
let key = null;
myMap.set(null, "aaa");
console.log(myMap.get(null)); aaa
console.log(myMap.get(key)); aaa
(4)字符串、数字、布尔值作为键值
同样只要键值=== 其value值都是相同的,即获取的是同一个键。
(5)对象、数组、函数
引用值,如果指向的地址是同一个地址,获取的也是同一个键;如果不是同一个地址,获取的就不是同一个键。
let key = {};
let key1 = key;
myMap.set(key, "aaa");
console.log(myMap.get({})); undefined
console.log(myMap.get(key)); aaa
console.log(myMap.get(key1)) aaa
2、for...of迭代Map对象
for...of可以迭代Map对象和Set对象,已经调用他们的方法得到的MapIterator和SetIterator对象,所以Map和Set是有序的。此处区别于Object对象
for...of
循环在每次迭代后会返回一个形式为[key,value]的数组。
let myMap = new Map();
myMap.set("name", "zhuzhu")
.set(23, 24)
.set(false, true)
.set(["1",2], ["js","html","css"])
.set({}, {a:1,b:2});
for(keyValue of myMap){
console.log(keyValue)
}