JavaScript 手动封装Set集合(包括求交并差集)

ES6的js新增了Set集合,为这门语言带来了集合数据结构,为了更深层次的理解Set集合底层封装机制,我们来手写一个Set集合。

首先要知道Set集合的内置方法和属性有哪些?

Set内置一个类似对象数组的一种数据结构,我们就用set数组来代替,同时还有一个size属性指向集合的总个数。

其他内置方法包括:增、删、查、遍历

接下来我们开始写代码:

'use strict'
//迭代器
const mySet = function () {
  const wm = new WeakMap();
  const InitPrivate = Symbol('private');
  function mySet(args) {
    this.set = [];
    // this.size=this.get();

    this[InitPrivate](args);

    Object.defineProperties(this.set,{
      [Symbol.iterator]:{
        value:function(){
          return this;
        }
      },

      next:{
        value:function(){
          if(wm.get(this)[this.index]<this.set.length){
            return {value:this.set[wm.get(this)[this.index]++].value,done:false}
          }else{
            wm.get(this)[this.index]=0;
            return {value:undefined,done:true};
          }
        }.bind(this)
      },
      
    });

    Object.defineProperty(this,"size",{
      value:0,
      enumerable:false,
      writable:true,
      configurable:false,
    })

    wm.get(this)[this.verIf]();
  }

  //初始化私有属性和方法
  mySet.prototype[InitPrivate] = function (args) {
    Object.defineProperties(this,{
      verIf:{
        value:Symbol('private')
      },
      index:{
        value:Symbol('private')
      }
    })
    const privateMembers = wm.get(this) || {};
    privateMembers[this.index]=0;
    privateMembers[this.verIf] = Init.bind(this, args);
    wm.set(this, privateMembers);
  }

  //对初始赋值进行检测
  function Init(args) {
    args = args || [];
    if (!(args instanceof Array)) {
      throw new Error('参数必须是数组');
    }

    for (const value of args) {
      if (!this.has(value)) {
        this.set.push({ value: value });
      }
    }
    this.size=this.get();
  }

  Object.defineProperties(mySet.prototype, {
    delete: {
      value: function (data) {
        return this.set.some((item, i) => {
          if (item.value === data) {
            this.set.splice(i, 1);
            this.size=this.get();
            return true;
          }
        });
      }
    },

    add: {
      value: function (data) {
        if (!this.has(data) && data) {
          this.set.push({ value: data });
        }
        this.size=this.get();
        
        //返回this,以便链式调用
        return this;
      }
    },

    has: {
      value: function (data) {
        return this.set.some(item => item.value === data);
      }
    },

    clear:{
      value:function(){
        this.set.splice(0,this.set.length);
        this.size=this.get();
      }
    },

    get:{
      value:function(){
        return this.set.length;
      }
    },

    entries:{
      value:function(){
          let Entries=[];
          for(const value of this){
            Entries.push({key:value,value:value});
          }
          return Entries;
      }
    },

    values:{
      value(){
        let SetIterator=[];
        this.set.forEach(element => {
          SetIterator.push(element);
        });

        return SetIterator;
      }
    },

    [Symbol.iterator]:{
      value:function(){
        return this.set;
      }
    },
  })


  return mySet;
}();

在封装Set的时候我发现,js原生Set集合对象是能够被迭代的,由此可见内部一定是部署了一个迭代器的,于是我也在mySet集合中部署了迭代器,让所有mySet的对象的迭代器都指向内部的this.set,而且使用了一个私有属性index,用处就是让同一个对象可被重复迭代;

写完上述代码后,你可以通过实例对象对里面的方法进行检查,接下里我们用自己实现的Set集合来实现集合交并差的操作:

//交集
let overSet=Array.from(s).filter(item=>x.has(item));
console.log(overSet);  //[2, 3, 4]

//并集
let andSet=[...new mySet([...s,...x])];
console.log(andSet);   //[1, 2, 3, 4, 6]

//差集
let diffSet=Array.from(s).filter(item=>!x.has(item));

console.log(diffSet); //[1]

可以发现和原生集合是一模一样的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值