【数据结构与算法】用JS普通对象手撸一个Set集合

320 阅读3分钟

这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战

介绍

我们在数学概念中,集合是一组不同对象的集,而且在ES 2015中Set类已经是JavaScript API的一部分了。本期我们将用普通对象来模拟实现一个这样的类,虽然非常简单,但也是一个重要的数据结构,我们就通过这个模拟实现来加深对其的认识吧。

概念

集合是由一组无序且唯一(即不能重复)的项组成的。该数据结构使用了与有限集合相同的数学概念,但应用在计算机科学的数据结构中。

正文

1.基本结构

 class MySet{
     constructor(){
         this.items = {};
         this.size = 0;
     }
     has(item){}
     add(item){}
     delete(item){}
     clear(){}
     values(){}
 }

 export default MySet;

我们用items来做对象存储,用size来记录当前集合内元素的数量。

  • has:判断传入元素是否存在,返回一个布尔类型。
  • add:推送一个元素进入集合内,返回当前集合。
  • delete:删除一个集合内的元素,返回一个布尔类型。
  • clear:清空当前集合。
  • values:返回集合内元素的值。

2.has方法

has(item){
    return Object.prototype.hasOwnProperty.call(this.items,item)
}

Object.prototype.hasOwnProperty来判断当前存储器中是否存在某个元素。当然你可以可以使用items in item来判断。但是hasOwnProperty更加准确因为,in方法会判断当前对象原型链上是否有属性匹配,而hasOwnProperty则只会判断当前对象是否有属性匹配。

还有同学会想为什么用call呢,直接items.hasOwnProperty(item)不行么,其实是可以的,但是最好用Object.prototype.hasOwnProperty去调用,因为items是一个自定义对象,而自定义对象有可能原型链会移除或者改变,这样自定义的对象就可能没有hasOwnProperty方法,在一些检查工具中就会显示错误。

3.add方法

add(item) {
    if (!this.has(item)) {
        this.items[item] = item;
        this.size = Object.keys(this.items).length;
    }
    return this;
}

推一个元素进入集合中,要判断是否集合内存在,因为刚刚也说了集合是一组不同对象的集,所以我们要用has方法先判断一下是否已经存在,如果存在那么就存储起来,然后用Object.keys的长度重置一下当前集合的数量。返回集合本身,这样我们还可以进行链式的调用了,即myset.add(1).add(2).add(3)。

4.delete方法

delete(item) {
    if (!this.has(item)) return false;
    delete this.items[item];
    this.size = Object.keys(this.items).length;
    return true;
}

删除非常简单判断一下是否存在,如果不存在返回false证明删除失败,成功则返回true,当然别忘了要更新一下当前集合数量。

5.clear方法

clear() {
    this.items = {}
    this.size = 0;
}

清空很简单就是把集合重置一下,这里为了方便用了重新指向新内存地址,你可以可以变量删除其内容,这里不做赘述。

6.values方法

values() {
    let values = [];
    for (const key in this.items) {
        if (this.items.hasOwnProperty(key)) {
            values.push(key)
        }
    }
    return values;
}

获取当前集合各个元素的值我们用了for..in方法,遍历后的值塞入数组后将数组返回,当然你可以使用Object.values方法可以直接返回数组。但缺点是Object.values是ES 2017的API,兼容状况会不如for..in。

7.使用

import MySet from "./js/MySet"
const myset= new MySet();

myset.has(1)  // false

myset.add(1).add(1).add(2).add(3)

myset.has(1) // true

myset.delete(2) // true

myset.values() // [1,3]

myset.clear()

myset.size  // 0

我们可以看到,has可以判断元素是否存在于该集合,链式推送元素,也可以删除元素,以及返回当前元素数据等方法,我们均已完成了模拟实现。

结语

集合看似是一个非常简单的数据结构,但是我们在我们开发实践中意义重大。比如,集合常被用于查询的设计和处理,它可是数据库是大多数应用程序的根基。我们通过学习模拟是希望大家对数据结构加深理解,工作中合理使用,使我们的设计的数据更清晰有序,更便于维护。