1
class Pair {
    constructor(x, y) {
        this.x = x
        this.y = y
    }
    // TODO ?
}
const set = new Set()
set.add(new Pair(1, 2))

How to make follow statement to return true?

set.has(new Pair(1, 2)) // -> false

(We can override equals and hashCode of Pair class in Java)

djy
  • 585
  • 3
  • 13

2 Answers2

4

The references will only be equal if they point to the same value in memory - new will (by default) create a new object, which cannot be === to a separate one. I suppose one option would be to return an existing x,y Pair instance if it's been constructed earlier:

const pairs = {};
function getMakePair(x, y) {
  const str = x + ',' + y;
  if (pairs[str]) {
    return pairs[str];
  }
  const pair = new Pair(x, y);
  pairs[str] = pair;
  return pair;

}
class Pair {
  constructor(x, y) {
    this.x = x
    this.y = y
  }
}

const set = new Set()
set.add(getMakePair(1, 2))
console.log(set.has(getMakePair(1, 2)))

Or, if you wanted all action to be in the constructor, you can have the constructor explicitly create / return the instance, though it's a bit less clear IMO, and it's kind of odd to see:

class Pair {
  constructor(x, y) {
    const str = x + ',' + y;
    if (Pair.pairs[str]) {
      return Pair.pairs[str];
    }
    const instance = Object.create(Pair.prototype);
    instance.x = x
    instance.y = y
    Pair.pairs[str] = instance;
    return instance;
  }
}
Pair.pairs = {};

const set = new Set()
set.add(new Pair(1, 2))
console.log(set.has(new Pair(1, 2)))

Of course, if you use a method like this to cache instances, you shouldn't mutate the .x / .y property of the instance, else the caching mechanism will harder to reason about. If you want that sort of mutable caching functionality, you might consider using .find on an array of instances instead.

CertainPerformance
  • 260,466
  • 31
  • 181
  • 209
3

Overriding the equality check is infeasible right now: https://stackoverflow.com/a/29759699/7803502

Instead, you can extend the Set class to create your own PairSet.

class Pair {
  constructor(x, y) {
    this._x = x
    this._y = y
  }
  
  toString() {
    return [
      this._x,
      this._y,
    ].join(',')
  }
}

class PairSet extends Set {
  add(pair) {
    return super.add(pair.toString())
  }
  
  has(pair) {
    return super.has(pair.toString())
  }
  
  delete(pair) {
    return super.delete(pair.toString())
  }
}

(function test() {
  const set = new PairSet()
  set.add(new Pair(1, 2))
  console.log(set.has(new Pair(1, 2))) // true
  console.log(set.has(new Pair(2, 1))) // false
})()
Tim Wong
  • 532
  • 3
  • 9