覆盖JavaScript中比较运算符的默认行为

Che*_*tan 10 javascript inheritance overriding class object

我有一个自定义的Javascript类(使用John Resig的简单Javascript继承创建).我希望能够比较这个类的两个实例,使用==,<,>,>=,和<=符号.

如何覆盖自定义类的比较器?

Lee*_*ine 10

尝试重写valueOf().然后你可以写这样的东西:

if (obj1.valueOf() === obj2.valueOf())
if (obj1.valueOf() < obj2.valueOf())
if (obj1.valueOf() > obj2.valueOf())
Run Code Online (Sandbox Code Playgroud)

因此,每当我需要一个特殊的JavaScript对象类型来覆盖比较时,我只需将valueOf添加到原型中.它对于原始类型也很有用,因为valueOf只返回值.

请注意空值.

  • valueOf的好处是你不需要显式调用它obj1> obj2会为你调用valueOf.排序数组时,有时会调用toString(在FF上),所以也要实现它. (2认同)

HMR*_*HMR 5

Lee 是正确的,如果你实现了 valueOf,那么在比较对象时(不是用 === 或 !===),这将被使用,但你也必须使用 toString 因为它在出于某种原因对数组进行排序时使用。

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);
Run Code Online (Sandbox Code Playgroud)


Gab*_*iel 4

这不能以您暗示的方式完成(尽管那会很甜蜜)。我见过的最好的方法是在原型上实现一组方法来充当比较:

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.
Run Code Online (Sandbox Code Playgroud)

我今天在工作中再次思考这个问题,有一种替代方法可以利用标准比较运算符,但可以进行自定义对象比较。诀窍是在代表可比较状态的对象上拥有一个属性(getter)。这将要求在给定相同的可比较属性的情况下,对象的所有实例都计算为相同的数值。作为一个例子,我们来谈谈向量:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

然后当你设置向量时:

var v1 = new Vector(1,1,1);
var v2 = new Vector(1,0,1);
v1.comp() > v2.comp() // true
Run Code Online (Sandbox Code Playgroud)

当然,只有当您处理的是可以分解为简单数值表达式的值的对象时,这才有效,但好处是获得基本效果的实现代码相当低,您甚至可以制作对象本身是一个函数,返回其组成部分的数值表达式。

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;
}
Run Code Online (Sandbox Code Playgroud)

现在您可以通过简单的数字比较获得该对象的所有优点,而且它甚至有点简洁。

  • @Gabriel [这里有一篇文章](http://www.2ality.com/2011/12/fake-operator-overloading.html) 有点类似于现在已经消失的帖子。 (2认同)