Proposal: [Symbol.equals]

kai zhu kaizhu256 at gmail.com
Sat Jan 19 05:28:39 UTC 2019


the most reliable/idiot-proof equality is by avoiding classes altogether; stick with plain json-objects and compare their canonical-json-representation like this real-world example [1]:

```
/*jslint devel*/
(function () {
    "use strict";
    var jsonStringifyCanonical;

    jsonStringifyCanonical = function (obj, replacer, space) {
    /*
     * this function will JSON.stringify <obj>,
     * with object-keys sorted and circular-references removed
     */
        var circularSet;
        var stringify;
        var tmp;
        stringify = function (obj) {
        /*
         * this function will recursively JSON.stringify obj,
         * with object-keys sorted and circular-references removed
         */
            // if obj is not an object or function,
            // then JSON.stringify as normal
            if (!(
                obj
                && typeof obj === "object"
                && typeof obj.toJSON !== "function"
            )) {
                return JSON.stringify(obj);
            }
            // ignore circular-reference
            if (circularSet.has(obj)) {
                return;
            }
            circularSet.add(obj);
            // if obj is an array, then recurse its items
            if (Array.isArray(obj)) {
                tmp = "[" + obj.map(function (obj) {
                    // recurse
                    tmp = stringify(obj);
                    return (
                        typeof tmp === "string"
                        ? tmp
                        : "null"
                    );
                }).join(",") + "]";
                circularSet.delete(obj);
                return tmp;
            }
            // if obj is not an array,
            // then recurse its items with object-keys sorted
            tmp = "{" + Object.keys(obj).sort().map(function (key) {
                // recurse
                tmp = stringify(obj[key]);
                if (typeof tmp === "string") {
                    return JSON.stringify(key) + ":" + tmp;
                }
            }).filter(function (obj) {
                return typeof obj === "string";
            }).join(",") + "}";
            circularSet.delete(obj);
            return tmp;
        };
        circularSet = new Set();
        return JSON.stringify((
            (typeof obj === "object" && obj)
            // recurse
            ? JSON.parse(stringify(obj))
            : obj
        ), replacer, space);
    };

    // true
    console.assert(
        // {"data":{"x":1,"y":2,"z":3},"meta":{"label":"point #13"}}
        jsonStringifyCanonical({
            data: {x: 1, y: 2, z: 3},
            meta: {label: "point #32"}
        })
        // === {"data":{"x":1,"y":2,"z":3},"meta":{"label":"point #13"}}
        === jsonStringifyCanonical({
            meta: {label: "point #32"},
            data: {z: 3, y: 2, x: 1}
        })
    );
}());
```


[1] testing aa “==“ b by comparing their canonical json-representation
https://github.com/kaizhu256/node-utility2/blob/2018.12.30/test.js#L2903 <https://github.com/kaizhu256/node-utility2/blob/2018.12.30/test.js#L2903>
https://github.com/kaizhu256/node-utility2/blob/2018.12.30/lib.utility2.js#L2760 <https://github.com/kaizhu256/node-utility2/blob/2018.12.30/lib.utility2.js#L2760>


> On 18 Jan 2019, at 3:39 PM, Isiah Meadows <isiahmeadows at gmail.com> wrote:
> 
> Yeah, I agree. I'd suggest overloading `==`, but that'd risk serious web compat issues, especially if `null`/`undefined` aren't special-cased. I feel an `equals` instance method added to all builtins and an `Object.equals` attempting that method first before performing a shallow object comparison would be the best solution.
> On Fri, Jan 18, 2019 at 15:24 Jordan Harband <ljharb at gmail.com <mailto:ljharb at gmail.com>> wrote:
> It's pretty important that the meaning `===` not be able to change.
> 
> On Fri, Jan 18, 2019 at 10:33 AM ViliusCreator <viliuskubilius416 at gmail.com <mailto:viliuskubilius416 at gmail.com>> wrote:
> What about having Symbol.equals?
> 
> For example, for now this is what it does:
> 
> ```js
> 
> class Position { 
>     constructor(o) {
>         this.x = o.x instanceof Number ? o.x : 0
> 
>         this.y = o.y instanceof Number ? o.y : 0
> 
>         this.z = o.z instanceof Number ? o.z : 0
>     }
> }
> console.log(new Position({x: 10, y: 10, z: 10}) === new Position({x: 10, y: 10, z: 10})
> 
> ```
> Output is of course, false.
> With `Symbol.equals`, we could make it easier, instead of `instance.equals(otherInstance)`.
> 
>  
> 
> For example:
> 
> ```js
> 
> class Position {
> 
>     [Symbol.equals](oIn) {
>         return oIn.x === this.x && oIn.y === this.y && oIn.z === this.z
>     }
>     constructor(o) {
>         this.x = o.x instanceof Number ? o.x : 0
> 
>         this.y = o.y instanceof Number ? o.y : 0
> 
>         this.z = o.z instanceof Number ? o.z : 0
>     }
> }
> console.log(new Position({x: 10, y: 10, z: 10}) === new Position({x: 10, y: 10, z: 10})
> 
> ```
> Now output would be true.
> 
> This would save most of the time, instead of writing .equals and then surrounding everything with ().
> 
> 
>  <https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient>	Virus-free. www.avast.com <https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient> <x-msg://1/#m_-3789658945863370968_m_4203195586323233386_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>_______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20190118/6e75c869/attachment-0001.html>


More information about the es-discuss mailing list