Javascript:运算符重载

我已经使用JavaScript几天了,并且已经到了我想为我定义的对象重载运算符的地步。

在谷歌搜索了一段时间之后,似乎你不能正式做到这一点,但是有一些人声称有一些冗长的方式来执行这个动作。

基本上,我已经创建了一个Vector2类,并希望能够执行以下操作:

var x = new Vector2(10,10);
var y = new Vector2(10,10);

x += y; //This does not result in x being a vector with 20,20 as its x & y values.

相反,我必须这样做:

var x = new Vector2(10,10);
var y = new Vector2(10,10);

x = x.add(y); //This results in x being a vector with 20,20 as its x & y values. 

有没有一种方法可以在我的Vector2类中重载运算符?因为这看起来很丑陋。


答案 1

正如你所发现的,JavaScript不支持运算符重载。您可以最接近的是实现(当实例需要强制为字符串时,它将被调用)和(它将被调用以将其强制为数字,例如在用于加法时,或者在许多情况下将其用于串联时,因为尝试在连接之前进行加法), 这是非常有限的。两者都不允许您创建对象作为结果。同样,Proxy(在 ES2015 中添加)允许您拦截各种对象操作(包括属性访问),但同样不会让您控制 on 实例的结果。toStringvalueOf++Vector2+=Vector


但是,对于想要一个字符串或数字(而不是)来回答这个问题的人,这里有一些和 的例子。这些示例没有演示运算符重载,只是利用了 JavaScript 的内置处理转换为基元:Vector2valueOftoString

valueOf

此示例将对象属性的值加倍,以响应被强制转换为基元,例如通过 :val+

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)

或者使用ES2015的: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)

或者只是使用对象,没有构造函数:

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

此示例将对象属性的值转换为大写,以响应被强制转换为基元,例如通过 :val+

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

或者使用ES2015的: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

或者只是使用对象,没有构造函数:

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

答案 2

正如 T.J. 所说,你不能在 JavaScript 中重载运算符。但是,您可以利用该函数编写一个 hack,它看起来比每次都使用函数更好,但对向量施加了 x 和 y 介于 0 和 MAX_VALUE。代码如下:valueOfadd

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

然后你可以这样写方程式:

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]