web-dev-qa-db-fra.com

Remplacer la comparaison d'équivalence en Javascript

Est-il possible de remplacer la comparaison d'équivalence en Javascript?

Le plus proche que j'ai obtenu d'une solution est de définir la fonction valueOf et d'appeler valueOf avec un plus devant l'objet.

Cela marche.

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

Mais cela échoue.

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

Voici mes cas de test.

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

Démo ici: http://jsfiddle.net/tWyHg/5/

34
Larry Battle

En effet, l'opérateur == Ne compare pas uniquement les primitives, il n'appelle donc pas la fonction valueOf(). Les autres opérateurs que vous avez utilisés ne fonctionnent qu'avec des primitives. Je crains que vous ne puissiez pas réaliser une telle chose en Javascript. Voir http://www.2ality.com/2011/12/fake-operator-overloading.html pour plus de détails.

21
Corkscreewe

Ferroutage sur @Corkscreewe:

C'est parce que vous traitez avec des objets et les opérateurs d'équivalence vont seulement comparer si deux variables référencent le même objet, pas si les deux objets sont en quelque sorte égaux.

Une solution consiste à utiliser "+" devant les variables et à définir une méthode valueOf pour les objets. Cela appelle la méthode valueOf sur chaque objet pour "convertir" sa valeur en un nombre. Vous l'avez déjà trouvé, mais vous ne semblez pas en être très satisfait.

Une solution plus expressive pourrait être de définir une fonction d'égalité pour vos objets. En utilisant vos exemples ci-dessus:

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

Je sais que cela ne fait pas exactement ce que vous voulez (redéfinissez les opérateurs d'équivalence eux-mêmes), mais j'espère que cela vous rapprochera un peu.

14
Noah Freitas

Si c'est une comparaison complète d'objets que vous recherchez, vous pouvez utiliser quelque chose de similaire à cela.

/*
    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
CBusBus

vous pouvez utiliser la fonction ES6 Object.is() pour vérifier la propriété de l'objet.

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;
}
2
Khalid Azam