ES6学习笔记——集合类型之set与map

11-1. set 集合

一直以来,JS只能使用数组和对象来保存多个数据,缺乏像其他语言那样拥有丰富的集合类型。因此,ES6新增了两种集合类型(setmap),用于在不同的场景中发挥作用。

set用于存放不重复的数据

  1. 如何创建set集合
new Set(); //创建一个没有任何内容的set集合

new Set(iterable); //创建一个具有初始内容的set集合,内容来自于可迭代对象每一次迭代的结果
const s1 = new Set();
        console.log(s1);  // Set(0) {}
        
// 可以对数组与字符串进行去重
 const s2 = new Set("asdfasfasf");
        console.log(s2);   // Set(4) {"a", "s", "d", "f"}
        
const s2 = new Set([1,2,3,4,4,3,2,1,5]);
        console.log(s2);   // Set(5) {1, 2, 3, 4, 5}
  1. 如何对set集合进行后续操作
  • add(数据): 添加一个数据到set集合末尾,如果数据已存在,则不进行任何操作
    • set使用Object.is的方式判断两个数据是否相同,但是,针对+0和-0,set认为是相等
  • has(数据): 判断set中是否存在对应的数据
  • delete(数据):删除匹配的数据,返回是否删除成功
    -clear():清空整个set集合
  • size: 获取set集合中的元素数量,只读属性,无法重新赋值
  const s1 = new Set();
        s1.add(1);
        s1.add(2);
        s1.add(3);
        s1.add(1); //无效
        s1.add(+0);
        s1.add(-0); //无效
        console.log(s1);  // Set(4) {1, 2, 3,0}
        
        s1.has(3);  //true
        s1.has(5);  // false

		s1.delete(3);     // 返回 true  
		console.log(s1);  // Set(3) {1, 2,0}
		s1.delete(6);     // 返回 false  表示没有删除成功,因为该数据不存在。。

		s1.clear();        //清空整个set集合
		console.log(s1);  // Set(0) {}
		
		console.log("总数为:", s1.size);  // 0 
  1. 如何与数组进行相互转换
const s = new Set([x,x,x,x,x]);
// set本身也是一个可迭代对象,每次迭代的结果就是每一项的值
const arr = [...s];

数组与字符串去重,把去重后的保存到一个新数组(字符串)中;

 const arr = [45, 7, 2, 2, 34, 46, 6, 57, 8, 55, 6, 46];
        const result = [...new Set(arr)];
        console.log(result);  // [45, 7, 2, 34, 46, 6, 57, 8, 55]

        const str = "asf23sdfgsdgfsafasdfasfasfasfsafsagfdsfg";
        const s = [...new Set(str)].join("");
        console.log(s);
  1. 如何遍历

    1). 使用for-of循环
    2). 使用set中的实例方法forEach

注意:set集合中不存在下标,因此forEach中的回调的第二个参数和第一个参数是一致的,均表示set中的每一项

const s1 = new Set();

        s1.add(1);
        s1.add(2);
        s1.add(3);
        s1.add(1); //无效
        s1.add(+0);
        s1.add(-0); //无效

        // for (const item of s1) {
        //     console.log(item);  // {1, 2, 3, 0}
        // }

		//s1.forEach(item => {
        //   console.log(item);  // {1, 2, 3, 0}
        // })
	
        s1.forEach((item, index, s) => {
            console.log(item, index, s);
        })
11-2. set 应用
        // 两个数组的并集、交集、差集 (不能出现重复项),得到的结果是一个新数组
        const arr1 = [33, 22, 55, 33, 11, 33, 5];
        const arr2 = [22, 55, 77, 88, 88, 99, 99];

        //并集
        // const result = [...new Set(arr1.concat(arr2))];
        console.log("并集", [...new Set([...arr1, ...arr2])]);

        const cross = [...new Set(arr1)].filter(item => arr2.indexOf(item) >= 0);
        //交集
        console.log("交集", cross)

        //差集
        // console.log("差集", [...new Set([...arr1, ...arr2])].filter(item => arr1.indexOf(item) >= 0 && arr2.indexOf(item) < 0 || arr2.indexOf(item) >= 0 && arr1.indexOf(item) < 0))
        console.log("差集", [...new Set([...arr1, ...arr2])].filter(item => cross.indexOf(item) < 0))
11-3. 手写set
class MySet {
    constructor(iterator = []) {
        //验证是否是可迭代的对象
        if (typeof iterator[Symbol.iterator] !== "function") {
            throw new TypeError(`你提供的${iterator}不是一个可迭代的对象`)
        }
        this._datas = [];
        for (const item of iterator) {
            this.add(item);
        }
    }

    get size() {
        return this._datas.length;
    }

    add(data) {
        if (!this.has(data)) {
            this._datas.push(data);
        }
    }

    has(data) {
        for (const item of this._datas) {
            if (this.isEqual(data, item)) {
                return true;
            }
        }
        return false;
    }

    delete(data) {
        for (let i = 0; i < this._datas.length; i++) {
            const element = this._datas[i];
            if (this.isEqual(element, data)) {
                //删除
                this._datas.splice(i, 1);
                return true;
            }
        }
        return false;
    }

    clear() {
        this._datas.length = 0;
    }

    *[Symbol.iterator]() {
        for (const item of this._datas) {
            yield item;
        }
    }

    forEach(callback) {
        for (const item of this._datas) {
            callback(item, item, this);
        }
    }

    /**
     * 判断两个数据是否相等
     * @param {*} data1 
     * @param {*} data2 
     */
    isEqual(data1, data2) {
        if (data1 === 0 && data2 === 0) {
            return true;
        }
        return Object.is(data1, data2);
    }
}
11-4. map集合

map集合专门用于存储多个键值对数据。

在map出现之前,我们使用的是对象的方式来存储键值对,键是属性名,值是属性值。
键值对(key value pair)数据集合的特点:键不可重复

之前使用对象存储会有以下问题:

  • 键名只能是字符串
  • 获取数据的数量不方便
  • 键名容易跟原型上的名称冲突

1.如何创建map

new Map(); //创建一个空的map
new Map(iterable); //创建一个具有初始内容的map,初始内容来自于可迭代对象每一次迭代的结果,但是,
                  //它要求每一次迭代的结果必须是一个长度为2的数组,数组第一项表示键,数组的第二项表示值
const mp1 = new Map();
console.log(mp1);   // Map(0) {}

const mp2 = new Map([["a", 3], ["b", 4], ["c", 5]]);
console.log(mp2);   //  Map(3) {"a" => 3, "b" => 4, "c" => 5}
  1. 如何进行后续操作
  • size:只读属性,获取当前map中键的数量
  • set(键, 值):设置一个键值对,键和值可以是任何类型
    • 如果键不存在,则添加一项
    • 如果键已存在,则修改它的值
    • 比较键的方式和set相同 (Object.is)
  • get(键): 根据一个键得到对应的值
  • has(键):判断某个键是否存在
  • delete(键):删除指定的键
  • clear(): 清空map
	const mp2 = new Map([["a", 3], ["b", 4], ["c", 5]]);
	const obj = {};
	mp2.set(obj, 6456);  // Map(4) {"a" => 3, "b" => 4, "c" => 5, {…} => 6456}
	mp2.set("a", "abc"); // Map(4) {"a" => "abc", "b" => 4, "c" => 5, {…} => 6456}
	mp2.set(obj, 111);   // Map(4) {"a" => "abc", "b" => 4, "c" => 5, {…} => 111}
   console.log(mp2)
   
   console.log("总数:", mp2.size);  // 总数:3
   
   console.log(mp2.get("a"));  // abc
   console.log(mp2.get("d"));  // undefined
   
   console.log(mp2.has("a")); // true 
   
   console.log(mp2.delete("a")); // true   Map(3) {"b" => 4, "c" => 5, {…} => 111}

   console.log(mp2.clear()); //  Map(0) {}
  1. 和数组互相转换 (和set一样)
const mp = new Map([
            ["a", 3],
            ["c", 10],
            ["b", 4],
            ["c", 5]
        ]);
        const result = [...mp]
        console.log(result);  //0: (2) ["a", 3]
							  //1: (2) ["c", 5]
							  //2: (2) ["b", 4]
  1. 遍历
  • for-of,每次迭代得到的是一个长度为2的数组
  • forEach,通过回调函数遍历
    • 参数1:每一项的值
    • 参数2:每一项的键
    • 参数3:map本身
 const mp = new Map([
            ["a", 3],
            ["c", 10],
            ["b", 4],
            ["c", 5]
        ]);
         for (const item of mp) {  
            console.log(item );     //["a", 3]
									//["c", 5]
									//["b", 4]  								
         }
         for (const [key, value] of mp) {  // 解构了
            console.log(key, value)   //  a 3
									  //  c 5
									  //  b 4
         }
         
         mp.forEach((value, key, mp) => {
            console.log(value, key, mp);
        })
11-5. 手写map
class MyMap {
    constructor(iterable = []) {
        //验证是否是可迭代的对象
        if (typeof iterable[Symbol.iterator] !== "function") {
            throw new TypeError(`你提供的${iterable}不是一个可迭代的对象`)
        }
        this._datas = [];
        for (const item of iterable) {
            // item 也得是一个可迭代对象
            if (typeof item[Symbol.iterator] !== "function") {
                throw new TypeError(`你提供的${item}不是一个可迭代的对象`);
            }
            const iterator = item[Symbol.iterator]();
            const key = iterator.next().value;
            const value = iterator.next().value;
            this.set(key, value);
        }

    }

    set(key, value) {
        const obj = this._getObj(key);
        if (obj) {
            //修改
            obj.value = value;
        }
        else {
            this._datas.push({
                key,
                value
            })
        }
    }

    get(key) {
        const item = this._getObj(key);
        if (item) {
            return item.value;
        }
        return undefined;
    }

    get size() {
        return this._datas.length;
    }

    delete(key) {
        for (let i = 0; i < this._datas.length; i++) {
            const element = this._datas[i];
            if (this.isEqual(element.key, key)) {
                this._datas.splice(i, 1);
                return true;
            }
        }
        return false;
    }

    clear() {
        this._datas.length = 0;
    }

    /**
     * 根据key值从内部数组中,找到对应的数组项
     * @param {*} key 
     */
    _getObj(key) {
        for (const item of this._datas) {
            if (this.isEqual(item.key, key)) {
                return item;
            }
        }
    }

    has(key) {
        return this._getObj(key) !== undefined;
    }

    /**
     * 判断两个数据是否相等
     * @param {*} data1 
     * @param {*} data2 
     */
    isEqual(data1, data2) {
        if (data1 === 0 && data2 === 0) {
            return true;
        }
        return Object.is(data1, data2);
    }

    *[Symbol.iterator]() {
        for (const item of this._datas) {
            yield [item.key, item.value];
        }
    }

    forEach(callback) {
        for (const item of this._datas) {
            callback(item.value, item.key, this);
        }
    }
}
11-6.WeakSet 和 WeakMap
WeakSet

使用该集合,可以实现和set一样的功能,不同的是:

  1. 它内部存储的对象地址不会影响垃圾回收
  2. 只能添加对象
  3. 不能遍历(不是可迭代的对象)、没有size属性、没有forEach方法
	let obj = {
            name: "yj",
            age: 18
        };
        let obj2 = obj;
        const set = new Set();
        set.add(obj);

        obj = null;
        obj2 = null;
        console.log(set); // WeakSet {{value: {name: "yj", age: 18}}} 


	let obj = {
            name: "yj",
            age: 18
        };
        let obj2 = obj;
        const set = new WeakSet();
        set.add(obj);

        obj = null;
        obj2 = null;
        console.log(set); // WeakSet {{…}}  空
WeakMap

类似于map的集合,不同的是:

  1. 它的键存储的地址不会影响垃圾回收
  2. 它的键只能是对象
  3. 不能遍历(不是可迭代的对象)、没有size属性、没有forEach方法
<ul>
        <!-- { id:"1", name:"姓名1" } -->
        <li>1</li>
        <!-- { id:"2", name:"姓名2" } -->
        <li>2</li>
        <!-- { id:"3", name:"姓名3" } -->
        <li>3</li>
    </ul>
const wmap = new WeakMap();
        let lis = document.querySelectorAll("li");
        for (const li of lis) {
            wmap.set(li, {
                id: li.innerHTML,
                name: `姓名${li.innerHTML}`
            });
        }
        lis[0].remove();
        lis = null;
        console.log(wmap);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值