Js中的Map、Set类型

Map、Set类型


1.Map(映射)

创建同时实例化,传入可迭代对象(需要包含的是一个含键/值对数组),会按顺序插入

const m1 = new Map([
    ["key1", "val1"],
	["key2", "val2"],
	["key3", "val3"]
]);
console.log(m1.size); // 3  
//size属性返回大小(没有length)

console.log(m1.has("key4")); // false
console.log(m1.get("key4")); // undefined
m1.set("key4", "val4")
  .set("key5", "val5");
// set()返回映射本身,因此可以连续set
m1.delete("key5"); //删除一对键/值
m1.clear(); //删除全部

与Object只能使用数值、字符串或符号作为键不同,Map可以使用任何JavaScript数据类型作为键。


keys()、values()、entries()(默认 [Symbol.iterator])分别返回 键、值、键/值数组的迭代器

系统的迭代器默认也实现了iterable接口 所以可以给for...of ,Array.from传迭代器对象)自己定义的类型则需自己实现

class A{
    constructor(id){
        this.id=id;
    }
    [Symbol.iterator](){
        let max = this.id;
        let count = 0;
        return {
            next(){
                if(count<max){
                    count++;
                    return {done:false,value:count-1};
                }else{
                    return {done:true};
                }
            },
            [Symbol.iterator](){return this;}
        };
    }
}
let a = new A(5);

2.WeakMap

弱映射中的键只能是Object或者继承自Object的类型,值的类型没有限制。

const key1 = {id: 1},
	  key2 = {id: 2},
	  key3 = {id: 3};
// 使用嵌套数组初始化弱映射
const wm1 = new WeakMap([
	[key1, "val1"],
	[key2, "val2"],
	[key3, "val3"]
]);

也具备set()、get()、has()、delete()、clear()方法。

1.弱键

弱键是指这些键不属于正式的引用,不会阻止垃圾回收。

const wm = new WeakMap();
wm.set({}, "val");

由于没有标识符或对象有 “{} ” 的引用,所以下次垃圾回收时会回收这个键值对


2.不可迭代键

WeakMap没有也不允许迭代操作


3.如何使用弱映射

  • 私有变量:原理是将私有变量存于弱映射中,以对象为键(防止内存泄漏,不影响垃圾清理),放在WeakMap成员对象中

    例子中 id的键固定为符号Symbol(id) ,其他私有变量可以自定义

    let User = (() => {
        const w = new WeakMap();
        class User{
            constructor(id){
                this.id = id;
                if(id==undefined)
                    this.id = 0;
                this.idProperty = Symbol(id);
                this.setId(this.id);
            }
            setPrivate(property,value){
                let o = w.get(this) || {};
                o[property] = value;
                w.set(this,o);
            }
            getPrivate(property){
                let o = w.get(this);
                if(o!==undefined){
                    return o[property];
                }
                return undefined;
            }
            setId(id){
                this.setPrivate(this.idProperty,id);
            }
            getId(){
                return this.getPrivate(this.idProperty);
            }
        }
        return User;
    })();
    const user = new User("01");
    user.getId();
    

  • DOM节点关联数据

    const m = new Map();
    const loginButton = 
          document.querySelector('#login');
    // 给这个节点关联一些元数据
    m.set(loginButton, {disabled: true});
    

    如果dom节点被删除了,但由于Map中还保存着引用,所以对应的DOM节点仍然会逗留在内存中。

    如果使用Map则不会发生


3.Set(集合)

// 使用数组初始化集合
const s1 = new Set(["val1", "val2", "val3"]);
alert(s1.size); // 3 无length属性
// 使用自定义迭代器初始化集合
const s2 = new Set({
	[Symbol.iterator]: function*() {
		yield "val1";
		yield "val2";
		yield "val3";
	}
});
console.log(s2.size); // 3

console.log(s1.has("val4")); // false 布尔值
s1.add("val4")
  .add("val5");	//add()返回集合本身,因此可以连续add
s1.delete("val5");	// 删除值
s1.clear();	// 销毁所有值

集合中的元素不能重复 所以 add()和delete() 操作是幂等的

Set也可以迭代 keys() === values() (默认)都迭代值 ,entries() 迭代格式为[value, value]

也可对Set进行增强实现集合操作

class XSet extends Set {
    union(...sets) {
        return XSet.union(this, ...sets)
    }
    intersection(...sets) {
        return XSet.intersection(this, ...sets);
    }
    difference(set) {
        return XSet.difference(this, set);
    }
    symmetricDifference(set) {
        return XSet.symmetricDifference(this, set);
    }
    cartesianProduct(set) {
        return XSet.cartesianProduct(this, set);
    }
    powerSet() {
        return XSet.powerSet(this);
    }
    // 返回两个或更多集合的并集
    static union(a, ...bSets) {
        const unionSet = new XSet(a);
        for (const b of bSets) {
            for (const bValue of b) {
                unionSet.add(bValue);
            }
        }
        return unionSet;
    }
    // 返回两个或更多集合的交集
    static intersection(a, ...bSets) {
        const intersectionSet = new XSet(a);
        for (const aValue of intersectionSet) {
            for (const b of bSets) {
                if (!b.has(aValue)) {
                    intersectionSet.delete(aValue);
                }
            }
        }
        return intersectionSet;
    }
    // 返回两个集合的差集
    static difference(a, b) {
        const differenceSet = new XSet(a);
        for (const bValue of b) {
            if (a.has(bValue)) {
                differenceSet.delete(bValue);
            }
        }
        return differenceSet;
    }
    // 返回两个集合的对称差集
    static symmetricDifference(a, b) {
        // 按照定义,对称差集可以表达为
        return
        a.union(b).difference(a.intersection(b));
    }
    // 返回两个集合(数组对形式)的笛卡儿积
    // 必须返回数组集合,因为笛卡儿积可能包含相同值的对
    static cartesianProduct(a, b) {
        const cartesianProductSet = new XSet();
        for (const aValue of a) {
            for (const bValue of b) {
                cartesianProductSet.add([aValue,
                    bValue]);
            }
        }
        return cartesianProductSet;
    }
    // 返回一个集合的幂集
    static powerSet(a) {
        const powerSet = new XSet().add(new XSet());
        for (const aValue of a) {
            for (const set of new XSet(powerSet)) {
                powerSet.add(new XSet(set).add(aValue));
            }
        }
        return powerSet;
    }
}

4.WeakSet

弱集合中的值只能是Object对象

const val1 = {id: 1},
	  val2 = {id: 2},
	  val3 = {id: 3};
// 使用数组初始化弱集合
const ws1 = new WeakSet([val1, val2, val3]);

也拥有add()、has()、delete()、clear()方法,性质和Set类似。

- 弱值和WeakMap基本相同,不影响垃圾回收

- 也是不可以迭代的

- 给dom中的打标记时应用,比如在集合中的节点都禁用

  ```javascript
  const disabledElements = new WeakSet();
  const loginButton =
  document.querySelector('#login');
  // 通过加入对应集合,给这个节点打上“禁用”标签
  disabledElements.add(loginButton);

5.迭代与扩展

我们接触了有4种原生集合类型定义了默认迭代器:

  • Array
  • 定型数组
  • Map
  • Set

这意味着上述所有类型都支持顺序迭代,常见的处理语法有:

  • for...of

  • ( ... ) 拓展操作符

    let arr1 = [1, 2, 3];
    let arr2 = [...arr1];
    // 相当于分解为逗号分隔
    console.log(arr1); // [1, 2, 3]
    console.log(arr2); // [1, 2, 3]
    

  • 期待可迭代对象的构造函数

    let map1 = new Map([[1, 2], [3, 4]]);
    let set1 = new Set(["v1", "v2"]);
    
  • Array.from() 方法

posted @ 2021-05-19 17:46  王子饼干  阅读(687)  评论(0编辑  收藏  举报