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

19

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

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


在Javascript中,=不是比较运算符,而是赋值运算符。 - Peter Olson
糟糕,打错了。谢谢您指正。 - Chetan
1
请查看文章底部:“这个主题将在我正在进行的书籍《JavaScript 忍者秘笈》中深入讨论。预计将于 2008 年秋季发布。”- 尽管尚未发布,Resig 的书仍然是 JavaScript 领域的《终极毁灭战士》 :) - Šime Vidas
如何进行比较?标准是什么? - Šime Vidas
可能是JavaScript中重载算术运算符的重复问题? - Ciro Santilli OurBigBook.com
请在此处查看:https://dev59.com/b2kv5IYBdhLWcg3wghIi - Pacerier
3个回答

16

尝试重写valueOf()。然后你就可以编写类似于这样的内容:

if (obj1.valueOf() === obj2.valueOf())
if (obj1.valueOf() < obj2.valueOf())
if (obj1.valueOf() > obj2.valueOf())
所以每当我需要一个特殊的JavaScript对象类型来覆盖比较时,我只需将valueOf添加到原型中。对于基本类型也非常有效,因为valueOf只返回该值。只需注意空值。

3
valueOf的好处是你不需要显式地调用它,obj1> obj2将为您调用valueOf。在排序数组时,有时会调用toString(在FF上),因此也要实现它。 - HMR

6

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


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.

今天在工作中我进一步思考了这个问题,并且有一种替代方式可以利用标准比较运算符,但是具有自定义对象比较。窍门是在对象上有一个表示可比状态的属性(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);
  }
}

那么当您设置向量时:

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

当然,这仅适用于可以分解为简单数值表达式的对象,但好处是实现基本效果的代码非常少,甚至可以将对象本身作为返回其组件部分的数值表达式的函数。

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

现在您可以享受到对象所有的优点,而且数字比较也变得简单易懂了,甚至有些简洁。

我早就有所怀疑 :/ 无论如何还是谢谢。 - Chetan
前一段时间我看到了一种在Javascript中实现运算符重载的hacky方法:http://blogger.xs4all.nl/peterned/archive/2009/04/01/462517.aspx。我一直想尝试一下并看看是否能够改进它,但我从未有机会去做。 - Peter Olson
@PeterOlson那个链接已经失效了。如果你找到了,能否重新发布一下?谢谢。 - Gabriel
2
@Gabriel 这是一篇类似于现在已经消失的文章的帖子。链接 - Peter Olson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接