Javascript: operator overloading
As T.J. said, you cannot overload operators in JavaScript. However you can take advantage of the valueOf
function to write a hack which looks better than using functions like add
every time, but imposes the constraints on the vector that the x and y are between 0 and MAX_VALUE. Here is the code:
var MAX_VALUE = 1000000;
var Vector = function(a, b) {
var self = this;
//initialize the vector based on parameters
if (typeof(b) == "undefined") {
//if the b value is not passed in, assume a is the hash of a vector
self.y = a % MAX_VALUE;
self.x = (a - self.y) / MAX_VALUE;
} else {
//if b value is passed in, assume the x and the y coordinates are the constructors
self.x = a;
self.y = b;
}
//return a hash of the vector
this.valueOf = function() {
return self.x * MAX_VALUE + self.y;
};
};
var V = function(a, b) {
return new Vector(a, b);
};
Then you can write equations like this:
var a = V(1, 2); //a -> [1, 2]
var b = V(2, 4); //b -> [2, 4]
var c = V((2 * a + b) / 2); //c -> [2, 4]
As you've found, JavaScript doesn't support operator overloading. The closest you can come is to implement toString
(which will get called when the instance needs to be coerced to being a string) and valueOf
(which will get called to coerce it to a number, for instance when using +
for addition, or in many cases when using it for concatenation because +
tries to do addition before concatenation), which is pretty limited. Neither lets you create a Vector2
object as a result. Similarly, Proxy
(added in ES2015) lets you intercept various object operations (including property access), but again won't let you control the result of +=
on Vector
instances.
For people coming to this question who want a string or number as a result (instead of a Vector2
), though, here are examples of valueOf
and toString
. These examples do not demonstrate operator overloading, just taking advantage of JavaScript's built-in handling converting to primitives:
valueOf
This example doubles the value of an object's val
property in response to being coerced to a primitive, for instance via +
:
function Thing(val) {
this.val = val;
}
Thing.prototype.valueOf = function() {
// Here I'm just doubling it; you'd actually do your longAdd thing
return this.val * 2;
};
var a = new Thing(1);
var b = new Thing(2);
console.log(a + b); // 6 (1 * 2 + 2 * 2)
Or with ES2015's class
:
class Thing {
constructor(val) {
this.val = val;
}
valueOf() {
return this.val * 2;
}
}
const a = new Thing(1);
const b = new Thing(2);
console.log(a + b); // 6 (1 * 2 + 2 * 2)
Or just with objects, no constructors:
var thingPrototype = {
valueOf: function() {
return this.val * 2;
}
};
var a = Object.create(thingPrototype);
a.val = 1;
var b = Object.create(thingPrototype);
b.val = 2;
console.log(a + b); // 6 (1 * 2 + 2 * 2)
toString
This example converts the value of an object's val
property to upper case in response to being coerced to a primitive, for instance via +
:
function Thing(val) {
this.val = val;
}
Thing.prototype.toString = function() {
return this.val.toUpperCase();
};
var a = new Thing("a");
var b = new Thing("b");
console.log(a + b); // AB
Or with ES2015's class
:
class Thing {
constructor(val) {
this.val = val;
}
toString() {
return this.val.toUpperCase();
}
}
const a = new Thing("a");
const b = new Thing("b");
console.log(a + b); // AB
Or just with objects, no constructors:
var thingPrototype = {
toString: function() {
return this.val.toUpperCase();
}
};
var a = Object.create(thingPrototype);
a.val = "a";
var b = Object.create(thingPrototype);
b.val = "b";
console.log(a + b); // AB