Переопределить сравнение эквивалентности в Javascript

Можно ли переопределить сравнение эквивалентности в Javascript?

Ближайшим, к которому я пришел, является определение функции valueOf и вызов значенияOf с плюсом перед объектом.

Это работает.

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

Но это не удается.

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

Вот мои тестовые примеры.

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.");
});

Демо здесь: http://jsfiddle.net/tWyHg/5/

Ответ 1

Это потому, что оператор == не сравнивает только примитивы, поэтому не вызывает функцию valueOf(). Другие используемые вами операторы работают только с примитивами. Боюсь, вы не можете достичь такой вещи в Javascript. Подробнее см. http://www.2ality.com/2011/12/fake-operator-overloading.html.

Ответ 2

Piggybacking на @Corkscreewe:

Это связано с тем, что вы имеете дело с объектами, и операторы эквивалентности будут только сравнивать, ссылаются ли две переменные на один и тот же объект, а не на то, что оба объекта как-то равны.

Одним из решений является использование "+" перед переменными и определение метода valueOf для объектов. Это вызывает метод valueOf для каждого объекта, чтобы "отличить" его значение от номера. Вы уже нашли это, но, по понятным причинам, не очень довольны им.

Более выразительным решением может быть определение эквивалентной функции для ваших объектов. Используя приведенные выше примеры:

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

Я знаю, что это не делает именно то, что вы хотите (переопределите сами операторы эквивалентности), но, надеюсь, он поможет вам немного ближе.

Ответ 3

Если это полное сравнение объектов, которое вы ищете, вы можете использовать что-то похожее на это.

/*
    Object.equals

    Desc:       Compares an object 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 properties are equivalent */
    return true;
}

Ответ 4

Вы можете использовать функцию ES6 Object.is() для проверки свойства объекта.

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;
}