admin管理员组

文章数量:1314246

I'm trying to implement custom equality and relational operations using equals and pareTo methods. However, I get wrong results. Please help me figure our where I'm doing wrong.

var Person = function () {
this.age = null;
this.name = null;
};

Person.prototype.equals = function (that) {
    if (this.age === that.age) return true;
    else return false;
    };

Person.prototypepareTo = function (that) {
    return this.age - that.age;
    };

var p1 = new Person();
var p2 = new Person();

p1.age = 10;
p2.age = 20;

document.writeln(p1 < p2); // this should be true but evaluates to false.

I'm trying to implement custom equality and relational operations using equals and pareTo methods. However, I get wrong results. Please help me figure our where I'm doing wrong.

var Person = function () {
this.age = null;
this.name = null;
};

Person.prototype.equals = function (that) {
    if (this.age === that.age) return true;
    else return false;
    };

Person.prototype.pareTo = function (that) {
    return this.age - that.age;
    };

var p1 = new Person();
var p2 = new Person();

p1.age = 10;
p2.age = 20;

document.writeln(p1 < p2); // this should be true but evaluates to false.
Share Improve this question asked Jul 28, 2015 at 14:25 user1176058user1176058 6761 gold badge9 silver badges23 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 7

JavaScript doesn't have operator overloading, and > doesn't call any methods on your objects, so p1 < p2 won't use your equals or pareTo.

To do that parison, you'd use:

document.writeln(p1.pareTo(p2) < 0);

That said, you can implement valueOf and have it return age. valueOf does get called as part of > between objects:

function Person(age) {
    this.age = age;
    this.name = null;
}

Object.defineProperty(Person.prototype, "valueOf", {
    value: function () {
        return this.age;
    },
    writable: true,
    configurable: true,
});

Or in code written since ES2015 became universally-supported in non-obsolete browsers:

class Person {
    constructor(age) {
        this.age = age;
        this.name = null;
    }

    valueOf() {
        return this.age;
    }
}

Live Example:

class Person {
    constructor(age) {
        this.age = age;
        this.name = null;
    }

    valueOf() {
        return this.age;
    }
}

const p1 = new Person(10);
const p2 = new Person(20);

console.log("p1 < p2: " + (p1 < p2)); // true
console.log("p1 > p2: " + (p1 > p2)); // false

Beware though that p1 == p2 and p1 === p2 will always be false, even if age is the same:

class Person {
    constructor(age) {
        this.age = age;
        this.name = null;
    }

    valueOf() {
        return this.age;
    }
}

const p1 = new Person(10); // Same age
const p2 = new Person(10); // Same age

console.log("p1 == p2:  " + (p1 == p2));  // false!
console.log("p1 === p2: " + (p1 === p2)); // false!

valueOf is invoked when the JavaScript engine needs to convert the object to a primitive; it doesn't do that for == or === unless it has to because the other operand is a primitive. So you'd have to define equals and explicitly call it (p1.equals(p2)), or force the parison to be between the primitives (+p1 === +p2), which is error-prone.

Revisiting this question and working with node v18.13.0, I found that relational operators between objects invoke the valueOf method, and if not available, then invoke the toString method. A String representation can be built to allow parison of most object types (assuming you can build the String representation as needed).

The following example illustrates all these cases by menting in/out the two versions of toString or the valueOf method:

import assert from 'node:assert/strict';

export class ComparableDate {

    // private instance variables
    #year
    #month
    #date

    constructor(year, month, date) {
        this.#year = year;
        this.#month = month;
        this.#date = date;
    }

    // Relational operators > < invoke the toString method.
    // Observe that this fails for paring dates in general
    // toString() {
    //     console.log("toString invoked");
    //     return ""+this.#year+"-"+this.#month+"-"+this.#date;
    // }

    // Zero-left padding, makes the string parison work as expected
    toString() {
        console.log("toString invoked");
        return (""+this.#year).padStart(4,'0')+"-"+(""+this.#month).padStart(2,'0')+"-"+(""+this.#date).padStart(2,'0');
    }


    // valueOf called over toString if present
    valueOf() {
        console.log("valueOf invoked");
        return this.#date + this.#month*31 + this.#year*366;
    }

}


// Test dates
let d1 = new ComparableDate(2023,2,15);
let d2 = new ComparableDate(2023,10,31);

// Test cases
assert(d2>d1, `${d2} must be greater than ${d1}`);
assert(d1<d2, `${d1} must be less than ${d2}`);

本文标签: Object comparison in Javascript using equals and compareTo methodsStack Overflow