# Symbol.equal - a way to define the weak equals operator on objects

**URL:** <https://es.discourse.group/t/symbol-equal-a-way-to-define-the-weak-equals-operator-on-objects/2651>\
**Category:** 💡 Ideas\
**Created:** [September 12, 2026, 4:43pm UTC](https://es.discourse.group/t/symbol-equal-a-way-to-define-the-weak-equals-operator-on-objects/2651 "2026-09-12T16:43:25Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![YeesterPlus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/yeesterplus/32/2520_2.png) [@YeesterPlus](https://es.discourse.group/u/YeesterPlus)\
**Post date:** [September 12, 2026, 4:43pm UTC](https://es.discourse.group/t/symbol-equal-a-way-to-define-the-weak-equals-operator-on-objects/2651/1 "2026-09-12T16:43:25Z")

</div>

I propose something new for object comparison called `Symbol.equal`.

The `==` operator should call the `Symbol.equal` method if the left hand side is an object or only the right hand side is an object.

example:

```js
class Box{
    #value=0;
    constructor(value){
        this.#value=value;
    }
    get value(){
        return this.#value;
    }
    [Symbol.equals](other){
        return other instanceof Box && other.value == this.value;
    }
}
assert(new Box(0) == new Box(0))

```

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [September 13, 2026, 1:26am UTC](https://es.discourse.group/t/symbol-equal-a-way-to-define-the-weak-equals-operator-on-objects/2651/2 "2026-09-13T01:26:11Z")

</div>

Some previous related discussions:

> [@Symbol.equal protocol](https://es.discourse.group/t/symbol-equal-protocol/594):
>
> class Sample { constructor(value) { this.#internal = value } [Symbol.equal](input) { if (input instanceof Sample) { return this.#internal === input.#internal } return false } } const foo = new Sample(1) const bar = new Sample(1) foo === bar // here change `Strict Equality Comparison` semantics? Object.is(foo, bar) // ? // or new grammar? References: [ECMAScript® 2024 Language&nbsp;Specification](https://tc39.es/ecma262/#sec-object.is)[ECMAScript® 2024 Language&nbsp;Specification](https://tc39.es/ecma262/#sec-strict-equality-comparison)[ECMAScript® 202…](https://tc39.es/ecma262/#sec-abstract-equality-comparison)

> <https://github.com/tc39/proposal-array-equality/issues/6>
>
> I feel this is ripe for a symbol that allows extending and modifying the equalit…y check. Library precedent is rather lacking (unless you consider \[Fantasy Land's Setoid spec\](https://github.com/fantasyland/fantasy-land#setoid) and its implementers as precedent), but there is a common \`.equals\` idiom that's emerged that I've noticed.
> 
> For language precedent, it's pretty strong. Here's a few right off the top of my head:
> 
> \- Java: \`public boolean equals(Object other)\`
> \- C++: \`boolean operator==(T other)\`
> \- Rust: \`std::cmp::Eq\<T\>\`, used by its \`==\` operator
> \- Haskell: \[\`Data.Eq\`\](https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Eq.html)
> 
> For naming, I propose \`Symbol.equals\`. This goes along with the idiom most are already using. And for standard library containers:
> 
> \- Error objects: identical name and message and deep equal own expando properties. Stack should not be considered for the purposes of this.
> \- RegExp objects: identical pattern and equivalent flags (\`/gi\` and \`/ig\` are considered equivalent).
> \- Arrays: identical length and deep-equal entries, but ignore expando properties
> \- Maps: size is identical, each key of \`this\` is deep-equal with a key in \`other\` and their corresponding entries are also deep-equal
> - The idea is that these should be compared deeply in the same way objects are, just instead of string equality, it's deep object equality.
> - Algorithm note: \[I've tried to distill that into something sufficiently fast here\](https://github.com/isiahmeadows/clean-assert/blob/master/lib/match.js#L246-L312). Either you'll need to encode similar in the spec or leave it implementation-defined for reasonable performance.
> \- Sets: size is identical and every key in \`this\` is deep-equal with a key in \`other\`
> - The idea is that these should be compared deeply in the same way objects are, just instead of string equality, it's deep object equality.
> - Algorithm note: \[I've tried to distill that into something sufficiently fast here\](https://github.com/isiahmeadows/clean-assert/blob/master/lib/match.js#L314-L383). Either you'll need to encode similar in the spec or leave it implementation-defined for reasonable performance.
> \- Array buffers, shared array buffers, and array buffer views: equal byte data
> \- Promises: identical status and deep-equal value if settled, reference identity if pending
> 
> The default behavior should still of course be the standard algorithm, and it's left implied that types of course also need to be equal.
> 
> \-----
> 
> I could also see HTML wanting to hook into this as well:
> 
> \- Event: \`detail\` deep-equal, \`eventPhase\` and mutable properties ignored, all other properties identical
> \- Node: children deep-equal
> \- Element: attributes and children deep-equal
> \- CharacterData: data equal
> \- Range: equivalent contents
> \- Request: equivalent target/headers/etc.
> \- And so on

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [September 13, 2026, 10:44pm UTC](https://es.discourse.group/t/symbol-equal-a-way-to-define-the-weak-equals-operator-on-objects/2651/3 "2026-09-13T22:44:02Z")

</div>

Why? What's the problem you're trying to solve?

---

<div class="post-metadata">

**Author:** ![YeesterPlus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/yeesterplus/32/2520_2.png) [@YeesterPlus](https://es.discourse.group/u/YeesterPlus)\
**Post date:** [September 13, 2026, 10:48pm UTC](https://es.discourse.group/t/symbol-equal-a-way-to-define-the-weak-equals-operator-on-objects/2651/4 "2026-09-13T22:48:46Z")

</div>

Other libraries might have different equality method names which makes it inconsistent and you might end up trying to call undefined or being too strict

btw: the other proposals solve this issue too and I don't care if you do mine or not

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [September 13, 2026, 11:06pm UTC](https://es.discourse.group/t/symbol-equal-a-way-to-define-the-weak-equals-operator-on-objects/2651/5 "2026-09-13T23:06:34Z")

</div>

Considering that `==` is aggressively discouraged in every form except perhaps `== null`, why would it be a good idea to begin encouraging its use?

What would be the benefit of a consistent way of comparing arbitrary objects? Two different kinds of objects are only comparable if they know about each other, in which case they'd need to both participate in the API, which they could do just by agreeing on a method name.

---

<div class="post-metadata">

**Author:** ![YeesterPlus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/yeesterplus/32/2520_2.png) [@YeesterPlus](https://es.discourse.group/u/YeesterPlus)\
**Post date:** [September 13, 2026, 11:14pm UTC](https://es.discourse.group/t/symbol-equal-a-way-to-define-the-weak-equals-operator-on-objects/2651/6 "2026-09-13T23:14:51Z")

</div>

code verbosity for general purpose library usage

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [September 14, 2026, 3:09am UTC](https://es.discourse.group/t/symbol-equal-a-way-to-define-the-weak-equals-operator-on-objects/2651/7 "2026-09-14T03:09:35Z")

</div>

`x == y` invisibly calling a protocol seems extremely less readable than `x.equals(y)` or the equivalent, to me.

---

<div class="post-metadata">

**Author:** ![YeesterPlus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/yeesterplus/32/2520_2.png) [@YeesterPlus](https://es.discourse.group/u/YeesterPlus)\
**Post date:** [September 14, 2026, 9:01pm UTC](https://es.discourse.group/t/symbol-equal-a-way-to-define-the-weak-equals-operator-on-objects/2651/8 "2026-09-14T21:01:26Z")

</div>

well, at least its less verbose

---

<div class="post-metadata">

**Author:** ![WebReflection](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/webreflection/32/248_2.png) [@WebReflection](https://es.discourse.group/u/WebReflection)\
**Post date:** [September 16, 2026, 11:55am UTC](https://es.discourse.group/t/symbol-equal-a-way-to-define-the-weak-equals-operator-on-objects/2651/9 "2026-09-16T11:55:20Z")

</div>

> [@ljharb](#):
>
> `x == y` invisibly calling a protocol seems extremely less readable than `x.equals(y)` or the equivalent, to me.

`valueOf` enters the conversation:

```javascript
({ valueOf: () => 123 }) == 123

```

I think anything more elegant than that would be great _and_ because indeed `==` is rare out there and old code won't be affected, I believe this idea is not that bad, just the name (maybe?) as I'd go for `Symbol.eqeq` instead or `Symbol.equality` as described on MDN [Equality (==) - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality)

**edit** I also agree `x.equals(y)` doesn't need to check for `Symbol.equality in obj` to branch `==` from `===` but still, `==` via symbol would be cool **but** I also think for `null` or `undefined` comparison that protocol should not be called or it will break working code with good intents.

---

<div class="post-metadata">

**Author:** ![WebReflection](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/webreflection/32/248_2.png) [@WebReflection](https://es.discourse.group/u/WebReflection)\
**Post date:** [September 16, 2026, 12:07pm UTC](https://es.discourse.group/t/symbol-equal-a-way-to-define-the-weak-equals-operator-on-objects/2651/10 "2026-09-16T12:07:16Z")

</div>

On a second though, wouldn't `Object.equal(a, b)` help solving the operator hidden gotcha and help comparing via:

- returns `true` if `Object.is(a, b)`
- returns `true` if `a == b`
- returns `true` if both objects have a `Symbol.equal` attached or inherited and `a[Symbol.equal](b)` and `b[Symbol.equal](a))` are both `true`
- returns `false` otherwise

... or maybe not?
