提问者:小点点

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类中重载运算符?因为这看起来很丑陋。


共3个答案

匿名用户

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

但是,对于想要字符串或数字作为结果(而不是Vector2)的人来说,这里有value eOftoString的示例。这些示例没有演示运算符重载,只是利用了JavaScript的内置处理转换为原语:

此示例将对象的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)

匿名用户

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

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]

匿名用户

可以用两个数字打包成一个来做向量数学。在解释它是如何工作的之前,让我先展示一个例子:

let a = vec_pack([2,4]);
let b = vec_pack([1,2]);

let c = a+b; // Vector addition
let d = c-b; // Vector subtraction
let e = d*2; // Scalar multiplication
let f = e/2; // Scalar division

console.log(vec_unpack(c)); // [3, 6]
console.log(vec_unpack(d)); // [2, 4]
console.log(vec_unpack(e)); // [4, 8]
console.log(vec_unpack(f)); // [2, 4]

if(a === f) console.log("Equality works");
if(a > b) console.log("Y value takes priority");

我使用的事实是,如果您将两个数字移动X次,然后在将它们移回之前对它们进行加减,您将获得与一开始未移动它们相同的结果。类似地,标量乘除对移动的值对称工作。

JavaScript数字具有52位整数精度(64位浮点数),因此我将一个数字打包到更高可用的26位中,一个打包到更低的中。代码变得有点凌乱,因为我想支持有符号的数字。

function vec_pack(vec){
    return vec[1] * 67108864 + (vec[0] < 0 ? 33554432 | vec[0] : vec[0]);
}

function vec_unpack(number){
    switch(((number & 33554432) !== 0) * 1 + (number < 0) * 2){
        case(0):
            return [(number % 33554432),Math.trunc(number / 67108864)];
        break;
        case(1):
            return [(number % 33554432)-33554432,Math.trunc(number / 67108864)+1];
        break;
        case(2):
            return [(((number+33554432) % 33554432) + 33554432) % 33554432,Math.round(number / 67108864)];
        break;
        case(3):
            return [(number % 33554432),Math.trunc(number / 67108864)];
        break;
    }
}

我能看到的唯一缺点是x和y必须在3300万范围内,因为它们必须在26位以内。