在 JavaScript 中重载算术运算符?

IT技术 javascript operator-overloading
2021-01-27 08:36:56

考虑到这个 JavaScript“类”定义,这是我能想到的最好的表达这个问题的方式:

var Quota = function(hours, minutes, seconds){
    if (arguments.length === 3) {
        this.hours = hours;
        this.minutes = minutes;
        this.seconds = seconds;

        this.totalMilliseconds = Math.floor((hours * 3600000)) + Math.floor((minutes * 60000)) + Math.floor((seconds * 1000));
    }
    else if (arguments.length === 1) {
        this.totalMilliseconds = hours;

        this.hours = Math.floor(this.totalMilliseconds / 3600000);
        this.minutes = Math.floor((this.totalMilliseconds % 3600000) / 60000);
        this.seconds = Math.floor(((this.totalMilliseconds % 3600000) % 60000) / 1000);
    }

    this.padL = function(val){
        return (val.toString().length === 1) ? "0" + val : val;
    };

    this.toString = function(){
        return this.padL(this.hours) + ":" + this.padL(this.minutes) + ":" + this.padL(this.seconds);
    };

    this.valueOf = function(){
        return this.totalMilliseconds;
    };
};

以及以下测试设置代码:

var q1 = new Quota(23, 58, 50);
var q2 = new Quota(0, 1, 0);
var q3 = new Quota(0, 0, 10);

console.log("Quota 01 is " + q1.toString());    // Prints "Quota 01 is 23:58:50"
console.log("Quota 02 is " + q2.toString());    // Prints "Quota 02 is 00:01:00"
console.log("Quota 03 is " + q3.toString());    // Prints "Quota 03 is 00:00:10"

有什么方法可以使用加法运算符隐式创建q4Quota对象,如下所示......

var q4 = q1 + q2 + q3;
console.log("Quota 04 is " + q4.toString());    // Prints "Quota 04 is 86400000"

而不是诉诸……

var q4 = new Quota(q1 + q2 + q3);
console.log("Quota 04 is " + q4.toString());    // Prints "Quota 04 is 24:00:00"

如果不是,则该领域中通过算术运算符使自定义数字 JavaScript 对象可组合的最佳实践建议是什么?

6个回答

据我所知,Javascript(至少现在存在)不支持运算符重载。

我能建议的最好的方法是从其他几个对象中创建新配额对象的类方法。这是我的意思的一个快速示例:

// define an example "class"
var NumClass = function(value){
    this.value = value;
}
NumClass.prototype.toInteger = function(){
    return this.value;
}

// Add a static method that creates a new object from several others
NumClass.createFromObjects = function(){
    var newValue = 0;
    for (var i=0; i<arguments.length; i++){
        newValue += arguments[i].toInteger();
    }
    return new this(newValue)
}

并像这样使用它:

var n1 = new NumClass(1);
var n2 = new NumClass(2);
var n3 = new NumClass(3);

var combined = NumClass.createFromObjects(n1, n2, n3);
我有点恼火,从负操作数向其模运算符返回负值的语言不支持运算符重载。在这一点上,世界上的每个人都必须将 % 实现为 ((a%b)+b)%b
2021-04-02 08:36:56

抱歉不行。

对于回退,如果您安排了返回值,则可以使用方法链接

var q4 = q1.plus(p2).plus(q3);
在 CoffeeScript 中,您也可以删除一些括号 :)
2021-03-15 08:36:56
如果您的环境支持它,您还可以使用 currying 来获得更漂亮的 API: one(two)(three)
2021-04-06 08:36:56
@elliottcable 好+聪明的想法,虽然这对于乘法来说可能没问题,但即便如此,我认为它在典型的程序员思维方式中也不能很好地沟通。我还是会去的one.times(two).times(three);
2021-04-07 08:36:56

由于每个人都对我的其他答案投了反对票,因此我想发布实际上按预期工作的概念代码证明。

这已经在 chrome 和 IE 中进行了测试。

//Operator Overloading

var myClass = function () {

//Privates

var intValue = Number(0),
    stringValue = String('');

//Publics
this.valueOf = function () {
    if (this instanceof myClass) return intValue;
    return stringValue;
}

this.cast = function (type, call) {
    if (!type) return;
    if (!call) return type.bind(this);
    return call.bind(new type(this)).call(this);
}

}

//Derived class
var anotherClass = function () {

//Store the base reference
this.constructor = myClass.apply(this);

var myString = 'Test',
    myInt = 1;

this.valueOf = function () {
    if (this instanceof myClass) return myInt;
    return myString;
}

}


//Tests

var test = new myClass(),
anotherTest = new anotherClass(),
composed = test + anotherTest,
yaComposed = test.cast(Number, function () {
    return this + anotherTest
}),
yaCComposed = anotherTest.cast(Number, function () {
    return this + test;
}),
t = test.cast(anotherClass, function () {
    return this + anotherTest
}),
tt = anotherTest.cast(myClass, function () {
    return this + test;
});

debugger;

如果有人愿意给出技术解释为什么这还不够好,我会很高兴听到它!

如果派生 ....
2021-03-15 08:36:56
Jay,你能展示一下这将如何与 MyNumber 类一起工作来做算术(举个例子)?
2021-03-30 08:36:56
它是否仅仅因为类型包含单个 int 值而起作用?
2021-04-01 08:36:56

第二个建议:

var q4 = Quota.add(q1, q2, q3);

Paper.js 就是这样做的,例如添加点(docs):

var point = new Point(5, 10);
var result = point + 20;
console.log(result); // {x: 25, y: 30}

但它使用自己的自定义脚本解析器来实现

你能用一个小的示例代码解释这个技巧吗?谢谢。我看过示例代码。
2021-03-24 08:36:56
我还没有在 Paper.js 示例中看到对这个解析器的调用。它像一个非常聪明的评估吗?
2021-03-25 08:36:56
+20 将 20 添加到成员 x 和 y。2号线
2021-03-29 08:36:56
此代码段使用提供的自定义解析器进行解释 - 这不是标准的 javascript。
2021-04-03 08:36:56