Can I define custom operator overloads in Javascript? [duplicate]
Asked Answered
P

7

27

Is it possible to define custom operators between instances of a type in 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.)

Processional answered 15/1, 2011 at 14:26 Comment(0)
I
10

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 function that supports chaining.

Iridize answered 15/1, 2011 at 16:10 Comment(1)
I recently discovered chaining by using JQuery. It is extremely useful in certain cases. Thanks a lot for the sample!Processional
E
8

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

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)
Encomiastic answered 15/1, 2011 at 14:29 Comment(1)
Yes, I currently have a function in the prototype as well. However, I'm used to using == for equality checking. But if it is not possible, then I'll just forget about itProcessional
M
8

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)
Macomber answered 15/1, 2011 at 15:10 Comment(5)
That's also a possiblity, but a little bit ugly to be honest. I think I'll be better of using an equality function.Processional
It's not that ugly as you might think, because you may already have a toString function on your object for easier debugging. But then again, I wrote this answer just because you said you prefer the == operator to eq. functions. Use what you like the best. Cheers! :)Macomber
I do have a toString function indeed, but for equality checking it is easier to do v1.equalsTo(v2) than remembering you have to convert it to a String, as that is not the usual way of doing it - thanks alot anyways!Processional
+1 for a clever solution (even though it's definitely not one I'd ever want to use.Widely
Clever solution indeed. What if the x, y and z already contain some semicolons? We never restricted their type to int. The type of bug which will cause a silent failure and it is hard to diagnose, especially if it occurs to the 100th million records after a few hours of processing. Also, converting ints to strings for the sole reason to compare them is utterly inefficient.Dialectician
S
4

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

Sharrisharron answered 15/1, 2011 at 14:30 Comment(2)
That's nicely found, but the == operator does not seem to be 'hackable'.Processional
i really wish this link still workedElectronic
C
4

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:

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.

Cultivator answered 30/5, 2015 at 21:15 Comment(0)
L
1

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.

References

Lamentable answered 22/6, 2013 at 3:30 Comment(0)
P
1

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.

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

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

<!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>
Protuberancy answered 23/10, 2013 at 19:8 Comment(2)
I realize this is an old answer - not sure how this is relevant to the OP's question though?Nanceynanchang
While this could be useful knowledge, this doesn't actually answer the question.Calzada

© 2022 - 2024 — McMap. All rights reserved.