我可以在 Javascript 中定义自定义运算符重载吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4700085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 14:34:22  来源:igfitidea点击:

Can I define custom operator overloads in Javascript?

javascriptvectoroperator-overloadingdslequality

提问by pimvdb

Is it possible to define custom operators between instances of a type in JavaScript?

是否可以在 JavaScript 中的类型实例之间定义自定义运算符?

For example, given that I have a custom vector class, is it possible to use

例如,鉴于我有一个自定义向量类,是否可以使用

vect1 == vect2

to check for equality, whilst the underlying code would be something like this?

检查相等性,而底层代码将是这样的?

operator ==(a, b) {
    return a.x == b.x && a.y == b.y && a.z == b.z;
}

(This is nonsense of course.)

(这当然是废话。)

采纳答案by mckoss

I agree that the equal function on the vector prototype is the best solution. Note that you can also build other infix-like operators via chaining.

我同意向量原型上的相等函数是最好的解决方案。请注意,您还可以通过链接构建其他类似中缀的运算符。

function Vector(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
}

Vector.prototype.add = function (v2) {
    var v = new Vector(this.x + v2.x,
                       this.y + v2.y,
                       this.z + v2.z);
    return v;
}

Vector.prototype.equal = function (v2) {
    return this.x == v2.x && this.y == v2.y && this.z == v2.z;
}

You can see online sample here.

您可以在此处查看在线示例

Update: Here's a more extensive sample of creating a Factory functionthat supports chaining.

更新:这是创建支持链接的工厂函数的更广泛示例。

回答by Gumbo

No, JavaScript doesn't support operator overloading. You will need to write a method that does this:

不,JavaScript 不支持运算符重载。您将需要编写一个方法来执行此操作:

Vector.prototype.equalTo = function(other) {
    if (!(other instanceof Vector)) return false;
    return a.x == b.x && a.y == b.y && a.z == b.z;
}

Then you can use that method like:

然后您可以使用该方法,例如:

vect1.equalTo(vect2)

回答by gblazex

The best you can do if you want to stick with the ==operator:

如果您想坚持使用==运营商,您可以做的最好的事情:

function Vector(x, y, z) {
  this.x = x;
  this.y = y;
  this.z = z;
}

Vector.prototype.toString = function () {
  return this.x + ";" + this.y + ";" + this.z;
};

var a = new Vector(1, 2, 3);
var b = new Vector(1, 2, 3);
var c = new Vector(4, 5, 6);


alert( String(a) == b ); // true
alert( String(a) == c ); // false
alert( a == b + "" );    // true again (no object wrapper but a bit more ugly)

回答by miku

No, it's not part of the spec (which doesn't mean that there aren't some hacks).

不,它不是规范的一部分(这并不意味着没有一些 hacks)。

回答by Karlen

You can change built-in methods of objects in JavaScript, such as valueOf()method. For any two objects to apply the following operators >, <, <=, >=, -, +JavaScript takes the property valueOf()of each object, so it deals with operators kind of like this: obj1.valueOf() == obj2.valueOf()(this does behind the scenes). You can overwrite the valueOf()method depends on your needs. So for example:

您可以更改 JavaScript 中对象的内置方法,例如valueOf()方法。对于要应用以下运算符的任意两个对象,>, <, <=, >=, -, +JavaScript 获取valueOf()每个对象的属性,因此它处理运算符的方式如下:(obj1.valueOf() == obj2.valueOf()这在幕后进行)。您可以valueOf()根据需要覆盖该方法。例如:

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

Person.prototype.valueOf(){
    return this.age;
}

var p1 = new Person(20, "Bob"), 
    p2 = new Person(30, "Bony");

console.log(p1 > p2); //false
console.log(p1 < p2); //true
console.log(p2 - p1); //10
console.log(p2 + p1); //40

//for == you should the following
console.log(p2 >= p1 && p2 <= p1); // false

So this is not the precise answer for your question, but I think this can be an useful stuff for that kind of issues.

所以这不是您问题的准确答案,但我认为这对于此类问题可能是有用的。

回答by Paul Sweatte

Here is a simple emulation which tests for equality using the guard operator:

这是一个简单的模拟,它使用守卫运算符测试相等性:

function operator(node)
  {
  // Abstract the guard operator
  var guard = " && ";
  // Abstract the return statement
  var action = "return ";
  // return a function which compares two vector arguments
  return Function("a,b", action + "a.x" + node + "b.x" + guard + "a.y" + node + "b.y" + guard + "a.z" + node + "a.z" );
  }

//Pass equals to operator; pass vectors to returned Function
var foo = operator("==")({"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3});
var bar = operator("==")({"x":1,"y":2,"z":3},{"x":4,"y":5,"z":6});

//Result
console.log(["foo",foo,"bar",bar]);

For non-strict mode functions the array index (defined in 15.4) named data properties of an arguments object whose numeric name values are less than the number of formal parameters of the corresponding function object initially share their values with the corresponding argument bindings in the function's execution context. This means that changing the property changes the corresponding value of the argument binding and vice-versa. This correspondence is broken if such a property is deleted and then redefined or if the property is changed into an accessor property. For strict mode functions, the values of the arguments object‘s properties are simply a copy of the arguments passed to the function and there is no dynamic linkage between the property values and the formal parameter values.

对于非严格模式函数,参数对象的数组索引(在 15.4 中定义)命名数据属性,其数值名称值小于相应函数对象的形式参数数量,最初与函数中的相应参数绑定共享它们的值。执行上下文。这意味着更改属性会更改参数绑定的相应值,反之亦然。如果这样的属性被删除然后重新定义,或者如果该属性被更改为访问器属性,则此对应关系将被破坏。对于严格模式函数,参数对象的属性值只是传递给函数的参数的副本,并且属性值和形式参数值之间没有动态链接。

References

参考

回答by Asaf Katz

It isn't a direct answer for you question but it's worth to note.

这不是您问题的直接答案,但值得注意。

PaperScript is a simple extension of JavaScript that adds support for operator overloading to any object.

PaperScript 是 JavaScript 的一个简单扩展,它为任何对象添加了对运算符重载的支持。

It used for for making Vector graphics on top of HTML5 Canvas.

它用于在 HTML5 Canvas 之上制作矢量图形。

It parse PaperScript to JavaScript on script tag with type="text/paperscript":

它在 type="text/paperscript" 的脚本标签上将 PaperScript 解析为 JavaScript:

<!DOCTYPE html>
<html>
<head>
<!-- Load the Paper.js library -->
<script type="text/javascript" src="js/paper.js"></script>
<!-- Define inlined PaperScript associate it with myCanvas -->
<script type="text/paperscript" canvas="myCanvas">
  // Define a point to start with
  var point1 = new Point(10, 20);

  // Create a second point that is 4 times the first one.
  // This is the same as creating a new point with x and y
  // of point1 multiplied by 4:
  var point2 = point1 * 4;
  console.log(point2); // { x: 40, y: 80 }

  // Now we calculate the difference between the two.
  var point3 = point2 - point1;
  console.log(point3); // { x: 30, y: 60 }

  // Create yet another point, with a numeric value added to point3:
  var point4 = point3 + 30;
  console.log(point4); // { x: 60, y: 90 }

  // How about a third of that?
  var point5 = point4 / 3;
  console.log(point5); // { x: 20, y: 30 }

  // Multiplying two points with each other multiplies each 
  // coordinate seperately
  var point6 = point5 * new Point(3, 2);
  console.log(point6); // { x: 60, y: 60 }

  var point7 = new Point(10, 20);
  var point8 = point7 + { x: 100, y: 100 };
  console.log(point8); // { x: 110, y: 120 }

  // Adding size objects to points work too,
  // forcing them to be converted to a point first
  var point9 = point8 + new Size(50, 100);
  console.log(point9); // { x: 160, y: 220 }

  // And using the object notation for size works just as well:
  var point10 = point9 + { width: 40, height: 80 };
  console.log(point10); // { x: 200, y: 300 }

  // How about adding a point in array notation instead?
  var point5 = point10 + [100, 0];
  console.log(point5); // { x: 300, y: 300 }
</script>
</head>
<body>
  <canvas id="myCanvas" resize></canvas>
</body>
</html>