Javascript ES6集合(SET)类型✪ ω ✪

在这里插入图片描述

Javascript ES6集合(SET)类型✪ ω ✪


一、集合

集合(Set),是ES6中新出的数据类型,这于数学中的集合概念是一样的。
在讲解 JS 的集合之前,我觉得还是有必要先回顾一下数学集合中的主要分类:并集,交集,差集
在这里插入图片描述
JavaScript 集合特性

  • Set是ES6提供的新的数据结构,允许存储任何数据类型。
  • 天生去重性,每个元素都是唯一,互不相同,这是也是集合最主要的特点。
  • 可以根据插入的顺序迭代它的元素。

简单概况: 集合是一个无序且不重复的数据类型


二、利用其去重性👲🏻

上面已经提到过了,集合天生去重,那么可以利用集合的去重性去做一些事情

  • 数组去重:
    张三使用了障眼法,造出了多个假的张三,看看罗老师如何去治张三

    // const name = ['张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '罗翔']
    let names = Array(10).fill("张三", 0, 10)             // 也可以这样去添加多个张三
    names.push("罗翔");
    names = [...new Set(names)]
    console.log(names)
    
    ["张三", "罗翔"]
    

    是吧,使用集合一下就能破解张三的障眼法,揪出唯一的一个张三

  • 接下来看一个去重性的应用,不重复抽奖

    const res = new Set();
    const names = ["张三", "李四", "小明", "李华", "约翰", "Jone", "Mark", "Bill", "PrettyGirl"];
    while (res.size < 3) {
        res.add(names[Math.abs(parseInt(Math.random() * 8))])
    }
    console.log(res)
    

    程序逻辑: 使用到了random 随机选出一个名字,在将此名字添加到集合里,如果是重复的将不进行添加操作,循环条件为判断集合人数是否小于3


三、迭代Set

在讲解下面的内容前,有必要去了解一下集合中的数据结构。

  • 要先明白的是传统的索引方法是无法取出集合数据。

     const vegetable = new Set(["青菜", "萝卜", "苹果", "香蕉", "土豆", "橘子"]);
     for (let i=0; i < vegetable.size; i++) {
         // 无法取出, 输出结果为undefined
         console.log(vegetable[i])
     }
    
  • 因为集合没有索引的原因,使用for in 循环也是无法取值。

    const vegetable = new Set(["青菜", "萝卜", "苹果", "香蕉", "土豆", "橘子"]);
    // 循环不执行
    for (let key in vegetable) {
        console.log(key)
    }
    
  • 只有使用 for of 循环方式进行取值,才能有结果

    const vegetable = new Set(["青菜", "萝卜", "苹果", "香蕉", "土豆", "橘子"]);
    for (let value of vegetable) {
        console.log(value)
    }
    
    青菜
    萝卜
    苹果
    香蕉
    土豆
    橘子
    

四、集合实例对象的方法

1)、Set.prototype.add(value)

在Set对象尾部添加一个元素,并且返回该Set对象。

const vegetable = new Set(["青菜", "萝卜"]);
vegetable.add("苹果");
console.log(vegetable);

根据会返回该Set对象的原理,可以实现对于该Set对象的链式操作。

const vegetable = new Set(["青菜", "萝卜"]);
vegetable.add("苹果").add("香蕉").add("土豆").add("橘子");
console.log(vegetable);
{"青菜", "萝卜", "苹果", "香蕉", "土豆", "橘子"}

2)、Set.prototype.clear()

移除Set对象内的所有元素。

const vegetable = new Set(["青菜", "萝卜", "苹果", "香蕉", "土豆", "橘子"]);
vegetable.clear();
console.log(vegetable);     // 清空后集合为空

3)、Set.prototype.delete(value)

移除集合中与这个值相等的元素,并返回是否删除成功。
在执行删除操作前,程序内部会先执行Set.prototype.has(value),判断要删除的元素是否存在, 如果该元素存在,则在删除元素后返回 true,否则返回 false

const vegetable = new Set(["青菜", "萝卜", "苹果", "香蕉", "土豆", "橘子"]);
const r1 = vegetable.delete("萝卜");
const r2 = vegetable.delete("卜萝");
console.log(r1, r2);
true false

4)、Set.prototype.entries()

返回一个新的迭代器对象,该对象包含集合对象中的按插入顺序排列的所有元素的值的[value, value] 数组,因为集合只有值的存在,所以数组中的元素都是相等的。

const vegetable = new Set(["青菜", "萝卜", "苹果", "香蕉", "土豆", "橘子"]);
for (let [key, value] of vegetable.entries()) {
    console.log(key, value);
}

5)、Set.prototype.forEach(callbackFn[, thisArg])

按照插入顺序,为Set对象中的每一个值调用一次callBackFn。如果提供了thisArg参数,回调中的this会是这个参数。

参数如下:

  • callbackFn: 为集合中每个元素执行的回调函数,该函数接收三个参数:
    • currentValue: 正在被操作的元素。
    • currentKey:由于集合没有索引,所以 currentKey 也表示这个正在被操作的元素。
    • set:调用当前 forEach 方法的集合对象。
  • thisArg:回调函数执行过程中的 this 值。

演示代码: 👇

vegetable.forEach(function (currentValue, currentKey, set) {
    console.log(currentValue, currentKey, set)
})
青菜 青菜 Set(6){'青菜', '萝卜', '苹果', '香蕉', '土豆',…}
萝卜 萝卜 Set(6){'青菜', '萝卜', '苹果', '香蕉', '土豆',…}
......

6)、Set.prototype.has(value)

返回一个布尔值,表示该值在Set中存在与否。

const vegetable = new Set(["青菜", "萝卜", "苹果", "香蕉", "土豆", "橘子"]);
console.log(vegetable.has("土豆"));       // true
console.log(vegetable.has("豆土"));       // false

7)、Set.prototype.keys()

因为集合只有值的存在,与values()方法相同,返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。

const vegetable = new Set(["青菜", "萝卜", "苹果", "香蕉", "土豆", "橘子"]);
for (let item of vegetable.keys()) {
    console.log(item)
}
青菜
萝卜
苹果
香蕉
土豆
橘子

8)、Set.prototype.values()

返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。

const vegetable = new Set(["青菜", "萝卜", "苹果", "香蕉", "土豆", "橘子"]);
for (let item of vegetable.values()) {
    console.log(item)
}
青菜
萝卜
苹果
香蕉
土豆
橘子

9)、Set.prototype[@@iterator]()

返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。用法与 Set.prototype.keys()Set.prototype.values() 方法一样。

for (let item of vegetable[Symbol.iterator]()) {
    console.log(item)
}
青菜
萝卜
苹果
香蕉
土豆
橘子

实际上,Set.prototype.keys()Set.prototype.values() 方法返回也是一个迭代器对象,数据内容一致。使用 next() 方法进行观察。

const iterator = vegetable[Symbol.iterator]()
console.log("iterator:", iterator.next())
console.log("iterator:", iterator.next())

const keys = vegetable.keys()
console.log("keys:", keys.next())
console.log("keys:", keys.next())

const values = vegetable.values()
console.log("values:", values.next())
console.log("values:", values.next())

五、扩展集合方法

1)、向集合原型添加方法

/**
 * 更新(update)集合,添加来自 others 中的所有元素, 灵感来自Python
 * @param others: 可迭代对象
 * @return {Set<any>} 添加结果后集合
 */
Set.prototype.update = function (others) {
    if (others.constructor === Set) {
        for (let i of others) {
            this.add(i);
        }
    } else {
        for (let i = 0; i < others.length; i++) {
            this.add(others[i]);
        }
    }
    return this
}

/**
 * 更新集合,移除也存在于 others 中的元素,也就是移除两个集合中都存在的元素
 * @param elems 需要更新的另一集合
 * @return {Set<any>} 返回新的集合
 */
Set.prototype.difference_update = function (elems) {
    for (let e of elems) {
        if (this.has(e)) {
            this.delete(e);
        } else {
            this.add(e);
        }
    }
    return this
}

/**
 * 返回集合的差集方法, 灵感来自Python
 * @param set 需要比较的另一集合
 * @returns {Set<any>} 差集集合
 */
Set.prototype.difference = function (set) {
    const diff = new Set();
    for (let item of set) {
        if (!this.has(item)) {
            diff.add(item);
        }
    }
    return diff
}

/**
 * 返回集合的交集方法, 灵感来自Python
 * @param set 需要比较的另一集合
 * @returns {Set<any>} 交集集合
 */
Set.prototype.intersection = function (set) {
    const common = new Set();
    for (let item of set) {
        if (this.has(item)) {
            common.add(item);
        }
    }
    return common
}

/**
 * 返回集合的并集方法, 灵感来自Python
 * @param set 需要合并的另一集合
 * @returns {Set<any>} 合并集合
 */
Set.prototype.union = function (set) {
    return this.update(set)
}

/**
 * 获取集合长度
 * @return {number} 长度值
 */
Set.prototype.length = function () {
    return this.size;
}

2)、继承
如果想在不影响原本集合构造函数的前提下扩展集合的方法,可以使用继承集合的方式对其扩展。

class MySet extends Set {
    /**
     * 更新(update)集合,添加来自 others 中的所有元素, 灵感来自Python
     * @param others: 可迭代对象
     * @return {Set<any>} 添加结果后集合
     */
    update(others) {
        if (others.constructor === Set) {
            for (let i of others) {
                this.add(i);
            }
        } else {
            for (let i = 0; i < others.length; i++) {
                this.add(others[i]);
            }
        }
        return this
    }

    /**
     * 更新集合,移除也存在于 others 中的元素,也就是移除两个集合中都存在的元素
     * @param elems 需要更新的另一集合
     * @return {Set<any>} 返回新的集合
     */
    difference_update(elems) {
        for (let e of elems) {
            if (this.has(e)) {
                this.delete(e);
            } else {
                this.add(e);
            }
        }
        return this
    }

    /**
     * 返回集合的差集方法, 灵感来自Python
     * @param set 需要比较的另一集合
     * @returns {Set<any>} 差集集合
     */
    difference(set) {
        const diff = new Set();
        for (let item of set) {
            if (!this.has(item)) {
                diff.add(item);
            }
        }
        return diff
    }

    /**
     * 返回集合的交集方法, 灵感来自Python
     * @param set 需要比较的另一集合
     * @returns {Set<any>} 交集集合
     */
    intersection(set) {
        const common = new Set();
        for (let item of set) {
            if (this.has(item)) {
                common.add(item);
            }
        }
        return common
    }

    /**
     * 返回集合的并集方法, 灵感来自Python
     * @param set 需要合并的另一集合
     * @returns {Set<any>} 合并集合
     */
    union(set) {
        return this.update(set)
    }

    length() {
        return this.size;
    }
}

参考资料💖

官方文档:


相关博客👒

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值