ES6之前JS中只有两种数据结构:数组Array,对象Object
ES6中新增了两种数据结构Set Map,以及另外形式 WeakMap WeakSet
1. 集合Set
集合和数组的区别
- 数组:元素可以重复
- 集合:元素不可重复
构造集合
需要调用Set构造函数,无字面量方式,参数可以传入一个可迭代对象
const set1 = new Set();
set1.add("item1");
const set2 = new Set([1, 2, 3, 3]);
consoel.log(set2); // [1, 2, 3]
Set属性
set.size; // 返回set的大小
Set方法
add delete has clear forEach for-of
// 五种方法测试
const set = new Set(["item1", "item2", 1, 2]);
// add
set.add("3");
// delete
set.delete("3");
// has
set.has("3"); // false
// clear
set.clear();
// 遍历
set.forEach(item => console.log(item));
for( const item of set){
console.log(item);
}
2. WeakSet
WeakSet和Set的区别如下
- WeakSet只能存放对象类型
- 对于对象是弱引用,GC自动回收时不会将弱引用算在内,所以会自动回收
弱引用示意
let obj = { name: 'xs' };
const weakset = new WeakSet();
weakset.add(obj);
obj = null;
// 取消对{ name: 'xs' }的强引用
// 一段时间后GC会将weakmap中的obj对象回收
WeakSet的方法
- has delete add
- 无clear forEach for-of 所以存入WeakSet的东西无法获取,所以基本上没啥用
- 无size方法
WeakSet的应用:记录是否出现过
const weakset = new WeakSet();
class Person{
constructor(name){
weakset .add(this)
this.name = name
}
running() {
if(!weakset .has(this)) throw new Error("不能通过非构造方法创建出来的对象调用running方法");
console.log(`${this.name} is running`)
}
}
const p = new Person('xs');
p.running.call({name: 'kobe'});// 报错:不能通过非构造方法创建出来的对象调用running方法
p.running() // 可以调用
3. 映射Map
Map和对象的区别
- 对象中的key只能为字符串或者Symbol类型,Map没有限制,key可以为对象
- 对象不可以for-of/forEach遍历(可以用for-in遍历),但是Map可以
对象的声明
const map= new Map();
const obj1 = {name:'xs'};
map.set(obj1,'aaa');
console.log(map); // { { name: 'xs' } => 'aaa' } 为了区分对象,返回值用箭头表示映射
对象的属性
map.size
对象的方法
get set has delete clear forEach for-of
// 遍历
for(const item of map){
console.log(item);// 返回的是一个数组[key1, value1]
}
for(const [key, value] of map){
console.log(key, value);
}
4.WeakMap
WeakMap和Map的区别
- WeakMap中key只能是对象
- WeakMap对于key是弱引用
WeakMap的方法
- get set has delete
- 无clear方法 遍历方法
- 无size属性
WeakMap的应用:多层记录本
场景: Vue3响应式原理中收集的依赖以WeakMap形式组织起来
const obj1 = {
name: "xs",
age: 18,
};
const obj2 = {
name: "kobe",
age: 28,
};
function change1Name1() {
console.log("object1 change name1");
}
function change1Name2() {
console.log("object1 change name2");
}
function change1Age1() {
console.log("object1 change age1");
}
function change1Age2() {
console.log("object1 change age2");
}
function change2Name1() {
console.log("object2 change name1");
}
function change2Name2() {
console.log("object2 change name2");
}
// 1 创建weakMap
const weakmap = new WeakMap();
// 2.收集依赖结构
// 2.1对obj1收集响应函数
const mapObj1 = new Map();
mapObj1.set("name", [change1Name1, change1Name2]);
mapObj1.set("age", [change1Age1, change1Age2]);
weakmap.set(obj1, mapObj1);
// 2.2对obj2收集响应函数
const mapObj2 = new Map();
mapObj2.set("name", [change2Name1, change2Name2]);
weakmap.set(obj2, mapObj2);
// 3 监听改变,有很多实现形式,还可以用Proxy
let _name = obj1.name;
Object.defineProperty(obj1, "name", {
configurable: true,
enumerable: true,
get: function () {
return _name;
},
set: function (value) {
_name = value;
weakmap
.get(obj1)
.get("name")
.forEach((fn) => fn());
},
});
obj1.name = 12; // 函数change1Name1和change1Name2就会执行