FormidableLabs / react-fast-compare

fastest deep equal comparison for React
MIT License
1.59k stars 54 forks source link

Getters are not considered #65

Closed tonio-ramirez closed 4 years ago

tonio-ramirez commented 4 years ago
import isEqual from "react-fast-compare";

class MyClass {

    #a;

    constructor(a) {
        this.#a = a;
     }

    get a() {
        return this.#a;
    }
}

console.log(isEqual(new MyClass(1), new MyClass(2)); // prints "true"
kitten commented 4 years ago

There's no way to get to these two properties, because #a is completely private and hidden, and getters are defined as non-enumerable, e.g.

Object.keys(new MyClass(1)) // [] empty

const x = new MyClass(1)
for (const key in x) { /* no enumerable keys */ }

for (const key in x.constructor.prototype) {
  /* no enumerable prototype keys even */
}

That means there's virtually no enumerable property, e.g. differentiating factor on your class.

In stringification functions I'd personally consider two classes that aren't objects (x.constructor && x.constructor !== Object && keys.length === 0) to always be unique and compare them by reference equality. However, in a deep comparison function that's a bad assumption.

There's a solution though :) You can for instance forgo the use of private class properties and make #a visible, e.g. by naming it _a.

You could also provide a serialisation function, which is actually quite common:

class MyClass {
  // ...
  valueOf() {
    return this.#a;
  }
}

Or alternatively you can use toString maybe:

class MyClass {
  // ...
  toString() {
    return `[MyClass ${this.#a}]`;
  }
}

Currently, react-fast-compare due to being specialised doesn't support toJSON though.

tonio-ramirez commented 4 years ago

I see. I'll look into using serialization functions or toString, then. Thanks!