Compare equality of instances of a class with private property

82 Views Asked by At

How to make a class with private properties so lodash isEqual returns false when comparing any 2 instances with different items in the private properties?

For example, in the following code isEqual comparison of the 2 instances of the Bobcat class with different items results in true. I want to have false. Is there any Map method missing or anything?

const _ = require('lodash')

class Bobcat {
  #items;

  constructor() {
    this.#items = new Map()
  }

  set(key, value) {
    return this.#items.set(key, value)
  }

  get(key) {
    return this.#items.get(key)
  }

  has(key) {
    return this.#items.has(key)
  }

  delete(key) {
    return this.#items.delete(key)
  }

  clear() {
    this.#items.clear()
  }

  keys() {
    return this.#items.keys()
  }

  values() {
    return this.#items.values()
  }

  entries() {
    return this.#items.entries()
  }

  forEach(callbackFn, thisArg) {
    return this.#items.forEach(callbackFn, thisArg)
  }

  [Symbol.iterator]() {
    return this.#items[Symbol.iterator]()
  }
}

const cat1 = new Bobcat()
cat1.set('a', 1)

const cat2 = new Bobcat()
cat2.set('a', 2)

console.log(_.isEqual(cat1, cat2))
// true

Another requirement is to have the comparison outside of the class. No comparison method should be added to the class itself. For example, I don't want

class Bobcat {
  isEqual(otherCat) {
    ... 
  }
}

or any specific to lodash functionality like

class Bobcat {
  [Symbol.for('lodash.isEqual')](otherCat) {
    ... 
  }
}
1

There are 1 best solutions below

1
srgbnd On

Customizing toStringTag to return Map solves the issue for me without changing the downstream code on the isEqual comparison.

  get [Symbol.toStringTag]() {
    return 'Map'
  }

Entire code

const _ = require('lodash')

class Bobcat {
  #items

  constructor() {
    this.#items = new Map()
  }

  set(key, value) {
    return this.#items.set(key, value)
  }

  get(key) {
    return this.#items.get(key)
  }

  has(key) {
    return this.#items.has(key)
  }

  delete(key) {
    return this.#items.delete(key)
  }

  clear() {
    this.#items.clear()
  }

  keys() {
    return this.#items.keys()
  }

  values() {
    return this.#items.values()
  }

  entries() {
    return this.#items.entries()
  }

  forEach(callbackFn, thisArg) {
    return this.#items.forEach(callbackFn, thisArg)
  }

  [Symbol.iterator]() {
    return this.#items[Symbol.iterator]()
  }

  get size() {
    return this.#items.size
  }

  get [Symbol.toStringTag]() {
    return 'Map'
  }
}

const cat1 = new Bobcat()
cat1.set('a', 1)

const cat2 = new Bobcat()
cat2.set('a', 1)

// true
console.log('equal1', _.isEqual(cat1, cat2))

cat2.set('a', 2)

// false
console.log('equal2', _.isEqual(cat1, cat2))