JS学习笔记(十四)
本系列更多文章,可以查看专栏 JS学习笔记
文章目录
一、Map【映射】
使用 new
关键字和 Map
构造函数,可以创建一个空映射;传入一个可迭代对象,需要包含键/值对数组,且会按照迭代顺序插入到新映射实例中。
1. 初始化映射
通过 size
属性可以获取 Map
对象的大小
注:键不可以重复,否则会按添加顺序靠后的覆盖前面的
// 使用嵌套数组初始化映射
const m1 = new Map([
["k1", 100],
["k2", 200],
["k1", 100]
]);
console.log(m1); // Map(2) {'k1' => 100, 'k2' => 200}
// 使用自定义迭代器初始化映射
const m2 = new Map({
[Symbol.iterator]: function* () {
yield ["k1", 100];
yield ["k2", 200];
yield ["k1", 100];
}
});
console.log(m2.size); // 2
2. 基本API
在映射中作为键和值的对象及其它“集合”类型,在自己的内容或属性被修改时仍然保持不变
- (1)set(),初始化Map对象后,添加键/值对
- (2)get(),获取Map对象中指定键的值,并返回该值
- (3)has(),判断Map对象中是否包含指定的键,并返回布尔值
- (4)delete(),删除Map对象中指定键/值对
- (5)clear(),清空Map对象中所有键/值对
set()
方法返回映射实例,可以把多个操作连缀起来,包括初始化声明
const m = new Map();
const objKey = {},
objVal = {},
arrKey = [],
arrVal = [];
m.set(objKey, objVal);
m.set(arrKey, arrVal);
console.log(m.get(objKey)); // {}
console.log(m.get(arrKey)); // []
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']
console.log(m.delete(objKey)); // true【删除成功】
console.log(m.has(objKey)); // false
console.log(objKey, objVal); // {foo: 'foo'} {bar: 'bar'}
m.clear();
console.log(m); // Map(0) {size: 0}
3. 相等比较算法
注:Map
内部使用 SameValueZero
进行比较操作,以下内容参考 《ES标准中的相等比较算法 SameValue和SameValueZero》
== | === | SameValue | SameValueZero | |
---|---|---|---|---|
NaN和NaN | false | false | true | true |
+0和-0 | true | true | false | true |
0和+0 | true | true | true | true |
0和-0 | true | true | false | true |
const m = new Map([
[NaN, "NaN1"],
[NaN, "NaN2"],
[-0, "-0"],
[0, "0"],
[+0, "+0"]
]);
console.log(NaN == NaN, NaN === NaN, Object.is(NaN, NaN)); // false false true
console.log(+0 == -0, +0 === -0, Object.is(+0, -0)); // true true false
console.log(0 == +0, 0 === +0, Object.is(0, +0)); // true true true
console.log(0 == -0, 0 === -0, Object.is(0, -0)); // true true false
// Map中不允许两个相同的键
console.log(m); // Map(2) {NaN => 'NaN2', 0 => '+0'}
4. 顺序和迭代
映射实例会提供一个迭代器(iterator),能以插入顺序生成[key,value]形式的数组。可以通过 entries()
方法或者 symbol.iterator
属性取得这个迭代器。
entries()
或者[Symbol.iterator]()
:用于获取映射实例的迭代器
keys()
:用于获取映射实例的键,并且返回可以迭代对象
values()
:用于获取映射实例的值,并且返回可以迭代对象
const m = new Map([
["key3", 16],
["key5", 19],
["key1", 28]
]);
// 获取映射实例的迭代器 - 方式1
for (let entry of m.entries()) {
console.log(entry);
}
// 获取映射实例的迭代器 - 方式2
for (let iter of m[Symbol.iterator]()) {
console.log(iter);
}
// 获取映射实例所有的键
console.log(m.keys()); // MapIterator {'key3', 'key5', 'key1'}
// 获取映射实例所有的值
console.log(m.values()); // MapIterator {16, 19, 28}
二、WeakMap【弱映射】
1. 初始化弱映射
注:弱映射中的键只能是 Object
或者继承自 Object
的类型;值的类型没有限制。
const key1 = { id: "key1" };
const key2 = { id: "key2" };
const wm = new WeakMap([
[key1, "value1"],
[key2, "value2"]
]);
console.log(wm);
vm.set("key3", "value3"); // Uncaught ReferenceError: vm is not defined
2. 基本API
区别于Map
对象,没有 size
属性,也没有clear()
方法
- (1)set(),初始化Map对象后,添加键/值对
- (2)get(),获取Map对象中指定键的值,并返回该值
- (3)has(),判断Map对象中是否包含指定的键,并返回布尔值
- (4)delete(),删除Map对象中指定键/值对
3. 弱键
相比于 Map
对象会使用两个数组(一个存放键,一个存放值),原生的 WeakMap
持有的每个键对象的“弱引用”。
这意味着,在没有其它引用存在时,垃圾回收可以正常进行,其用于映射的键对象,只有被回收时才是有效的。
因此,弱映射对象是不可枚举的!!
三、Set【集合】
使用 new
关键字和 Set
构造函数,可以创建一个空集合;传入一个可迭代对象,需要包含插入到新集合实例中的元素
1. 初始化映射
通过 size
属性可以获取 Set
对象元素数量。
// 使用数组初始化集合
const s1 = new Set(["v1", "v2", "v3"]);
console.log(s1); // Set(3) {'v1', 'v2', 'v3'}
// 使用自定义迭代器初始化集合
const s2 = new Set({
[Symbol.iterator]: function* () {
yield "v1";
yield "v2";
yield "v3";
}
});
console.log(s2.size); // 3
2. 基本API
与 Map
类似, Set
可以包含任何 JavaScript数据类型作为值;用作值的对象和其他“集合”类型在自己的内容或属性被修改时,也不会改变。
- (1)add(),初始化Set对象后,增加值
- (2)has(),判断Set对象中是否包含指定的元素,并返回布尔值
- (3)delete(),删除Set对象中指定元素
- (4)clear(),清空Set对象中所有元素
add()
和 delete()
操作是幂等的(即执行多次,也相当于执行1次)
const s = new Set();
s.add("v1");
console.log(s.size); // 1
s.add("v1");
console.log(s.size); // 1
注:Set
内部同样使用 SameValueZero
进行比较操作
3. 顺序和迭代
Set
会维护值插入时的顺序,支持按顺序迭代。可以通过 values()
方法及别名方法 keys()
方法或者 symbol.iterator
属性取得这个迭代器。
values()
或者[Symbol.iterator]()
:用于获取集合实例的迭代器
keys()
:是values()
的别名方法
entries()
:可以按照插入顺序产生包含两个元素的数组,这两个元素是集合中每个值的重复出现。
const s3 = new Set(["val1"]);
for (let v of s3.values()) {
console.log(v); // val1
v = "newVal1";
console.log(v); // newVal1
console.log(s3.has(v)); // false
console.log(s3.has("val1")); // true
}
四、WeakSet【弱集合】
注:弱集合中的值只能是 Object
或者继承自 Object
的类型;值的类型没有限制。
1. 基本API
区别于Set
对象,没有 size
属性,也没有clear()
方法
- (1)add(),初始化WeakSet对象后,增加值
- (2)has(),判断WeakSet对象中是否包含指定的元素,并返回布尔值
- (3)delete(),删除WeakSet对象中指定元素
2. 用途
可以用于给对象打标签,便于当任何元素从DOM树中被删除,而立即释放其内存。
五、总结
1. Object、Map、WeakMap、Set、WeakSet对比与总结
Object | Map | WeakMap | Set | WeakSet | |
---|---|---|---|---|---|
键类型 | 只能 使用 数值、字符串或者symbol类型 | 可以 使用 任何JavaScript类型 | 只能 使用 Object类型或者继承自Object类型 | — | — |
值类型 | 无限制 | 无限制 | 无限制 | 可以 使用 任何JavaScript类型 | 只能 使用 Object类型或者继承自Object类型 |
size属性 | — | 有 | — | 有 | — |
迭代 | 可迭代 | 可迭代 | 不可迭代 | 可迭代 | 不可迭代 |
基本API | 自行查询 | set()、has()、get()、delete()、clear() | set()、has()、get()、delete() | add()、has()、delete()、clear() | add()、has()、delete() |
查找速度 | 自行查询 | set()、has()、get()、delete()、clear() | set()、has()、get()、delete() | add()、has()、delete()、clear() | add()、has()、delete() |
2. Object与Map的区别
- Object只能使用数值、字符串或Symbol作为键;Map可以使用任何JS数据类型作为键。
- Map与Object类似,映射的值是没有限制的。
- Map的键是有序的,Object的键是无序的
- Map的查找速度 > Object的查找速度
3. Map与Set的区别
- 两种数据类型查找速度均很快
- Map类型利用二维数组进行初始化,Set类型利用一维数组进行初始化
- Map数据类型称为字典,Set数据类型称为集合
- Map的键唯一,值不唯一;Set的值就是键,键是唯一的
- Map的键值对有序,Set的值无序
- Map的键不可以修改,值可以修改;Set不可以通过迭代器来修改值
- Map以键值对形式存在,Set的value就是其key
结尾
部分内容参考《ECMAScript 6 入门》《JavaScript权威指南》《JavaScript高级程序设计》,如有错误,欢迎评论区指正。