Override default behavior of comparison operators in JavaScript

Try overriding valueOf(). Then you can write stuff like this:

if (obj1.valueOf() === obj2.valueOf())
if (obj1.valueOf() < obj2.valueOf())
if (obj1.valueOf() > obj2.valueOf())

So whenever I need a special JavaScript object type to override the comparison I just add valueOf to the prototype. It works great for primitive types as well since valueOf just returns the value.

Just watch out for nulls.


Lee is correct, if you implement valueOf then when comparing objects (not with === or !===) this will be used but you'll have to use toString as well because it's used when sorting arrays for some reason.

function Test(value){
  this.value=value;
}
Test.prototype.toString=function(){
  console.log("tostring called");
  // could do something with case sensitiveness here
  return new String(this.valueOf());
}
Test.prototype.valueOf=function(){
  console.log("valueof called");
  return this.value;
}

var t1=new Test(11);
var t2=new Test(1.1);
var arr=[t1,t2];
console.log('sorted',arr.sort().map(o=>o.value));
console.log('larger',t1>=t2);

this cannot be done in the way that you are implying it should be done (though that would be sweet). The best way I have seen this done is to implement on the prototype a set of methods to act like comparatives:

gte : function( obj ){ // greater than or equal
  // return custom comparison with this as the object comparable on the left
},
gt : function( obj ){...}, // greater than but not equal
eq : function( obj ){...}, // equal to
// etc.

I was thinking about this problem somemore at work today and there is an alternate way to take advantage of the standard comparison operators but have custom object comparisons. The trick would be to have a property (getter) on the object that represented the comparable state. This would require that all instances of the object evaluate to the same numeric value given the same comparable properties. As an example let's talk vectors:

function Vector(x,y,z){
  this.comp = function(){
    // assuming these are floats you may wish to create a comparable level of
    // precision. But this gets the point across.
    return x + (y * 10) + (z * 100);
  }
}

then when you set up vectors:

var v1 = new Vector(1,1,1);
var v2 = new Vector(1,0,1);
v1.comp() > v2.comp() // true

This only works of course if you are dealing with objects that can be broken down into simple numeric expression of value, but the upside is that the implementation code to get the basic effect is pretty low and you could even go so far as to make the object itself a function that returns the numeric expression of it's component parts.

function Vector(x,y,z){
  var v = function v(){
    return v.x + (v.y * 10) + (v.z * 100);
  }
  v.x = x;
  v.y = y;
  v.z = z;
  return v;
}

now you have all the benefits of the object with easy numeric comparisons and it's even kinda terse.