JS笔记集合引用类型(下)
JS笔记集合引用类型(上)文章目录4.4 Map1 基本API2 顺序与迭代3 Object VS Map4.5 WeakMap1 基本API2 弱键3 不可迭代键4 使用弱映射4.6 Set1 基本API2 顺序与迭代3 定义正式集合操作(==待解决==)4.7 WeakSet1 基本API2 弱值3 不可迭代值4 使用弱集合4.8 迭代与扩展操作4.7 WeakSet1 基本API2 弱值3
文章目录
4.4 Map
1 基本API
// 1.构造方式
const map = new Map(); // 关键字和构造函数创建一个空映射
const map = new Map([ // 嵌套数组构造时初始化
["key1","v1"],
["key2","v2"],
["key3","v3"]
]);
console.log(map.size); // 3
console.log(map); // Map(3) { 'key1' => 'v1', 'key2' => 'v2', 'key3' => 'v3' }
// 2.方法
// set()用于添加键值对
map.set("key4","heyun");
console.log(map); /*Map(4) {
'key1' => 'v1',
'key2' => 'v2',
'key3' => 'v3',
'key4' => 'heyun'
}*/
// 也可以链式使用
const map = new Map().set("k1","v1");
map.set("k2","v2")
.set("k3","v3");
console.log(map); /*Map(3) { 'k1' => 'v1', 'k2' => 'v2', 'k3' => 'v3' }*/
// get()用于取值,has()用于查询
console.log(map.get("key4")); // heyun
console.log(map.has("key4")); // true
// delete()和clear()用于删值
map.delete("key2") /*Map(3) { 'key1' => 'v1', 'key3' => 'v3', 'key4' => 'heyun' }*/
map.clear(); /*Map(0) {}*/
Map与Object的区别:
- Object 的键必须是数值、字符串或者符号,而Map可以使用任何JS数据类型作为键,内部使用SameValueZero比较操作,相当于使用严格对象相等。
- Map会维护键值对的插入顺序
Map与Object的相同点:
- 映射的值没有限制
// SameValueZero出现冲突的情况
const m = new Map();
const a = 0/"",
b = 0/"",
pz = +0,
nz = -0;
console.log(a === b); // false
console.log(pz === nz); // true
m.set(a,"bar");
m.set(pz,"foo");
console.log(m.get(b)); // bar
console.log(m.get(nz)); // foo
2 顺序与迭代
entries()是默认迭代器,可以直接对映射实例进行扩展操作,把映射转换为数组。
const map = new Map([ // 嵌套数组构造时初始化
["key1","v1"],
["key2","v2"],
["key3","v3"]
]);
console.log(map.entries === map[Symbol.iterator]); // true
for(let m of map.entries()) {
console.log(m); /*[ 'key1', 'v1' ]
[ 'key2', 'v2' ]
[ 'key3', 'v3' ]
*/
}
console.log([...map]); /*[ [ 'key1', 'v1' ], [ 'key2', 'v2' ], [ 'key3', 'v3' ] ]*/
使用回调方式也可以实现同样的效果
const map = new Map([ // 嵌套数组构造时初始化
["key1","v1"],
["key2","v2"],
["key3","v3"]
]);
map.forEach((v,k) => console.log(`${v} -> ${k}`)) /*v1 -> key1
v2 -> key2
v3 -> key3*/
键、值在迭代器遍历时是可以修改的,但映射内部的引用则无法修改,这不会影响修改做为键、值对象的内部属性
const map = new Map([ // 嵌套数组构造时初始化
["key1","v1"],
]);
for(let key of map) {
key = "newKey";
console.log(key); // newKey
console.log(map.get("key1")); // v1
}
3 Object VS Map
- 内存上看Map大约可以比Object多存储50%的值
- 如果代码设计到大量的插入操作,那么选择Map会更合适
- 如果代码设计大量的查找操作,Object更适合
- 对于大多数的浏览器来说,Map的delete()操作比插入和查找来得更快,所以如果有大量的代码删除操作,选择Map
4.5 WeakMap
1 基本API
Map的兄弟类型,其API也是Map 的子集,weak描述的是JavaScript垃圾回收程序对待“弱映射”中键的方式, 弱映射 中的键只能是Object类型或者继承Object的类型(Map没有限制),值的类型没有限制。
const map = new WeakMap([
["key1","v1"],
]);
console.log(map); // 如果按照Map的构造方式会报错
const key1 = {}; // 给key1绑定成对象
const map = new WeakMap([
[key1,"v1"],
]);
console.log(map.get(key1)); // v1
// 其它的set(),has(),delete()与Map一致
2 弱键
意思就是这些键不属于正式的引用,不会阻止垃圾回收
const wm = new WeakMap()
wm.set({},"v"); // 这里进行初始化,因为没有指向这个键的其它引用,所以这段代码执行完就会被回收,然后成为一个空映射,同时由于值也没有被引用,所以值也会成为被回收的目标
// -------
const wm = new WeakMap()
const container = {
key:{}
}
wm.set(container.key,"v"); // 这里由于key一直被引用着,所以就不会成为垃圾回收的目标,只有手动赋值为null,然后垃圾回收程序再清理。
3 不可迭代键
因为WeakMap中的键值对任何时候都可能被销毁,所以没有必要提供迭代器的能力。WeakMap之所以限制只能使用对象作为主键,是为了保证只有通过键对象的引用才能取到值
4 使用弱映射
- 私有变量的实现
const wm = new WeakMap();
class User {
constructor(id) {
this.idProperty = Symbol('id');
this.setId(id);
}
setPrivate(property,value) {
const privateMembers = wm.get(this) || {};
privateMembers[property] = value;
wm.set(this,privateMembers);
}
getPrivate(property) {
return wm.get(this)[property];
}
setId(id) {
this.setPrivate(this.idProperty,id);
}
getId() {
return this.getPrivate(this.idProperty);
}
}
const users = new User(123);
console.log(users.getId()); // 123
users.setId(456);
console.log(users.getId()); //456
console.log(wm.get(users)[users.idProperty]); // 456
上面最后一行代码通过拿到对象的实例和弱映射就可以取得‘私有变量’,为了避免上诉情况发生,可以使用闭包。
const User = (() => {
const wm = new WeakMap();
class User {
constructor(id) {
this.idProperty = Symbol('id');
this.setId(id);
}
setPrivate(property,value) {
const privateMembers = wm.get(this) || {};
privateMembers[property] = value;
wm.set(this,privateMembers);
}
getPrivate(property) {
return wm.get(this)[property];
}
setId(id) {
this.setPrivate(this.idProperty,id);
}
getId() {
return this.getPrivate(this.idProperty);
}
}
return User;
})();
const users = new User(123);
console.log(users.getId()); // 123
users.setId(456);
console.log(users.getId()); // 456
console.log(wm.get(users)[users.idProperty]); //那么到这里就拿不到wm的值,也就无法对私有变量进行访问。
-
DOM节点元数据
因为WeakMap实例不会妨碍垃圾回收,所以非常适合保存关联元数据。
const m = new Map(); const loginBtn = document.querySelector('#login'); m.set(loginBtn,{disabled:true}); // 以上代码执行后,页面会发生变化,但是由于映射中还保存着按钮的引用,所以对应的DOM节点仍会逗留在内存中,除非手动删除,或者该映射自己被摧毁。 const m = new WeakMap(); // 但是如果是弱映射,当节点被删除后,垃圾回收程序会立即释放其内存。
4.6 Set
1 基本API
// 1.构造方法
const set1 = new Set(); // 空集合
const set2 = new Set(['v1','v2','v3']); // 使用数组初始化集合
// 2.方法
// add():往集合里面添加值
set2.add("heyun")
.add("luoyu");
console.log(set2); // Set(5) { 'v1', 'v2', 'v3', 'heyun', 'luoyu' }
// has():判断集合中是否有目标元素
console.log(set2.has("luoyu")); // true
console.log(set2.has("hhh")); // false
// size:取得集合的长度
console.log(set2.size); // 5
// delete():删除指定元素,返回一个布尔值
set2.delete("heyun")
console.log(set2); // Set(4) { 'v1', 'v2', 'v3', 'luoyu' }
// clear():销毁集合实例中的所有值
set2.clear()
console.log(set2); // Set(0) {}
Set和Map类似,可以包含任何JS类型作为值,集合也可以使用SameValueZero操作。用作值的对象和其他‘集合’类型在自己的内容或属性被修改时也不会改变
2 顺序与迭代
Set会维护插入时的顺序,因此支持按顺序迭代。通过values()或者keys()取得迭代器(Symbol.iterator也行,它会引用values())
const set2 = new Set(['v1','v2','v3']);
console.log(set2.values === set2[Symbol.iterator]); // true
console.log(set2.keys === set2[Symbol.iterator]); // true
const set2 = new Set(['v1','v2','v3']);
for(let v of set2) {
console.log(v); /*v1
v2
v3
*/
}
const set2 = new Set(['v1','v2','v3']);
console.log([...set2]); // [ 'v1', 'v2', 'v3' ]
// 其它的方法和Map的大致类似,有一点比较熟悉的是set中的元素不能重复。
const set2 = new Set(['v1','v2','v3',"v1"]);
console.log([...set2]); // [ 'v1', 'v2', 'v3' ]
3 定义正式集合操作(待解决)
开发中很多人喜欢自定义set函数库,这里有几个需要注意的点。
- 某些set操作是关联的,因此设计的方法必须要支持处理任意多个集合实例
- set保留插入顺序,所有方法返回的集合必须保持顺序。
- 尽可能高效使用内存
- 不修改已有的集合实例:如union()
一些常见的集合实例
// 1.返回两个或更多集合的并集书上177页,有点问题,后面遇到了再解决
4.7 WeakSet
1 基本API
Set的兄弟类型 ,weak描述的是JS垃圾回收程序对待‘弱结合’中值的方式。通用弱集合中的值只能是Object或者继承Object的值。
const set1 = new WeakSet(['v1','v2','v3']);
console.log(set1); // 报错
// ------------
const v1 = {str:'v1'},
v2 = {str:'v2'},
v3 = {str:'v3'}
const set1 = new WeakSet([v1,v2,v3]);
console.log(set1); // WeakSet { <items unknown> }
WeakSet的方法与Set类似。
2 弱值
这儿和WeakMap弱键中的操作相同,就是怎么让垃圾程序回收的问题(加个对弱值的引用就不会被回收)
3 不可迭代值
无法使用迭代器,刚刚在上面的set1中试了下,直接报错,提示set1不是课迭代对象。
4 使用弱集合
同WeakMap的使用弱映射。
4.8 迭代与扩展操作
有四种原生集合类型定义了默认迭代器:Array、所有定型数组、Map、Set
let itetableItems = [
Array.of(1,2),
typedArr = Int16Array.of(3,4),
new Map([5,6],[7,8]),
new Set([9,10])
];
for (const iterator of itetableItems) {
for (const x of iterator) {
console.log(x); /*
1
2
3
4
[5,6]
[7,8]
9
10*/
}
}
所有的这些类型都兼容扩展操作符,因此在对可迭代对象进行浅复制时特别有用。
更多推荐
所有评论(0)