Search code examples
javascriptoopdata-structuresthisvar

Stack and Sets implementation (this vs var)


I was watching freeCodeCamps data structures and algorithms JavaScript implementations video (https://www.youtube.com/watch?v=t2CEgPsws3U) and I've noticed Stacks used this keyword (4:49) while their implementation of sets used var (10:06).

I tried to implement my own implementation of Sets and receive an error TypeError: firstSet.forEach is not a function.

  1. Is this because I used this instead of var or did I make a mistake on the implementation?
  2. Why did the stack implementation use this instead of var?

My Set implementation:

let mySet = function(){
  this.collection = [];

  this.has = (elem) =>{
    return (this.collection.indexOf(elem)!==-1)
  }

  this.values = ()=>{
    return this.collection;
  }

  this.add = (elem)=>{
    if(!this.has(elem)){
      this.collection.push(elem)
      return true;
    }
    return false
  }

  this.remove = (elem)=>{
    if(this.has(elem)){
      let idx = this.collection.indexOf(elem);
      this.collection.splice(idx,1);
      return true;
    }
    return false;
  }

  this.size = ()=>{
    return this.collection.length;
  }

  this.union = (secondSet)=>{
    let unionSet = new mySet();
    let firstSet = this.collection.values();
    let second = secondSet.values();
    firstSet.forEach(function(e){
      unionSet.add(e);
    })
    second.forEach(function(e){
      unionSet.add(e)
    })
    return unionSet;
  }

  this.intersection = (secondSet)=>{
    let intersectionSet = new mySet();
    let firstSet = this.collection.values();
    let second = secondSet.values();
    firstSet.forEach(function(e){
      if(second.has(e)){
        intersectionSet.add(e);
      }
    })
    return intersectionSet;
  }

  this.difference = (secondSet)=>{
    let differenceSet = new mySet();
    let firstSet = this.collection.values();
    let second = secondSet.values();
    firstSet.forEach(function(e){
      if(!second.has(e)){
        differenceSet.add(e)
      }
    })
    return differenceSet;
  }

  this.subset = (secondSet)=>{
    let firstSet = this.collection.values();
    let second = secondSet.values();
    firstSet.every(function(e){
      if(second.has(e)){
        return true;
      }
    })
  }
}
let mySet1 = new mySet();
let mySet2 = new mySet();

mySet1.add(2)
mySet1.add(3)
mySet1.add(1)
mySet1.add(2)
mySet1.add(5)
mySet2.add(2)
mySet2.add(4);
mySet2.add(6);
console.log(mySet2.union(mySet1))

Solution

  • this.collection contains the array. Calling Array.prototype.values returns the array iterator. Array iterators don't have a forEach method.

    Just use this.collection instead of this.collection.values, and you'll be able to use forEach (referencing Array.prototype.forEach) on the result.

    let mySet = function(){
      this.collection = [];
    
      this.has = (elem) =>{
        return (this.collection.indexOf(elem)!==-1)
      }
    
      this.values = ()=>{
        return this.collection;
      }
    
      this.add = (elem)=>{
        if(!this.has(elem)){
          this.collection.push(elem)
          return true;
        }
        return false
      }
    
      this.remove = (elem)=>{
        if(this.has(elem)){
          let idx = this.collection.indexOf(elem);
          this.collection.splice(idx,1);
          return true;
        }
        return false;
      }
    
      this.size = ()=>{
        return this.collection.length;
      }
    
      this.union = (secondSet)=>{
        let unionSet = new mySet();
        let firstSet = this.collection;
        let second = secondSet.values();
        firstSet.forEach(function(e){
          unionSet.add(e);
        })
        second.forEach(function(e){
          unionSet.add(e)
        })
        return unionSet;
      }
    
      this.intersection = (secondSet)=>{
        let intersectionSet = new mySet();
        let firstSet = this.collection.values();
        let second = secondSet.values();
        firstSet.forEach(function(e){
          if(second.has(e)){
            intersectionSet.add(e);
          }
        })
        return intersectionSet;
      }
    
      this.difference = (secondSet)=>{
        let differenceSet = new mySet();
        let firstSet = this.collection.values();
        let second = secondSet.values();
        firstSet.forEach(function(e){
          if(!second.has(e)){
            differenceSet.add(e)
          }
        })
        return differenceSet;
      }
    
      this.subset = (secondSet)=>{
        let firstSet = this.collection.values();
        let second = secondSet.values();
        firstSet.every(function(e){
          if(second.has(e)){
            return true;
          }
        })
      }
    }
    let mySet1 = new mySet();
    let mySet2 = new mySet();
    
    mySet1.add(2)
    mySet1.add(3)
    mySet1.add(1)
    mySet1.add(2)
    mySet1.add(5)
    mySet2.add(2)
    mySet2.add(4);
    mySet2.add(6);
    console.log(mySet2.union(mySet1).collection)

    Or invoke the iterator.

    for (const e of firstSet) {