Override the Equivalence Comparison in Javascript

2020-01-25 11:10发布

Is it possible to override the equivalence comparison in Javascript?

The closest I have gotten to a solution is by defining the valueOf function and invoking valueOf with a plus in front of the object.

This works.

equal(+x == +y, true);

But this fails.

equal(x == y, true, "why does this fail.");

Here are my test cases.

var Obj = function (val) {
    this.value = val;
};
Obj.prototype.toString = function () {
    return this.value;
};
Obj.prototype.valueOf = function () {
    return this.value;
};
var x = new Obj(42);
var y = new Obj(42);
var z = new Obj(10);
test("Comparing custom objects", function () {
    equal(x >= y, true);
    equal(x <= y, true);
    equal(x >= z, true);
    equal(y >= z, true);
    equal(x.toString(), y.toString());
    equal(+x == +y, true);
    equal(x == y, true, "why does this fails.");
});

Demo here: http://jsfiddle.net/tWyHg/5/

4条回答
淡お忘
2楼-- · 2020-01-25 11:17

If it's full object comparison you're looking for then you might want to use something similar to this.

/*
    Object.equals

    Desc:       Compares an object's properties with another's, return true if the objects
                are identical.
    params:
        obj = Object for comparison
*/
Object.prototype.equals = function(obj)
{

    /*Make sure the object is of the same type as this*/
    if(typeof obj != typeof this)
        return false;

    /*Iterate through the properties of this object looking for a discrepancy between this and obj*/
    for(var property in this)
    {

        /*Return false if obj doesn't have the property or if its value doesn't match this' value*/
        if(typeof obj[property] == "undefined")
            return false;   
        if(obj[property] != this[property])
            return false;
    }

    /*Object's properties are equivalent */
    return true;
}
查看更多
闹够了就滚
3楼-- · 2020-01-25 11:18

That is because the == operator doesn't compare only primitives, therefore doesn't call the valueOf() function. Other operators you used do work with primitives only. I'm afraid you cannot achieve such thing in Javascript. See http://www.2ality.com/2011/12/fake-operator-overloading.html for some more details.

查看更多
做自己的国王
4楼-- · 2020-01-25 11:30

Piggybacking on @Corkscreewe:

This is because you are dealing with Objects and the equivalency operators are only going to compare whether two variables reference the same Object, not whether the two Objects are somehow equal.

One solution is to use "+" in front of the variables and define a valueOf method for the Objects. This calls the valueOf method on each object to "cast" its value to a Number. You have already found this, but understandably do not seem very satisfied with it.

A more expressive solution might be to define an equals function for your Objects. Using your examples above:

Obj.prototype.equals = function (o) {
    return this.valueOf() === o.valueOf();
};

var x = new Obj(42);
var y = new Obj(42);
var z = new Obj(10);

x.equals(y); // true
x.equals(z); // false

I know this doesn't do exactly what you want (redefine the equivalency operators themselves), but hopefully it will get you a little closer.

查看更多
SAY GOODBYE
5楼-- · 2020-01-25 11:32

you can use the ES6 Object.is() function to check the property of object.

Object.prototype.equals = function(obj)
{
    if(typeof obj != "Object")
        return false;
    for(var property in this)
    {
        if(!Object.is(obj[property], this[property]))
            return false;
    }
    return true;
}
查看更多
登录 后发表回答