在JavaScript中重载算术运算符?

Pet*_*McG 68 javascript operator-overloading

考虑到这个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;
    };
};
Run Code Online (Sandbox Code Playgroud)

以及以下测试设置代码:

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"
Run Code Online (Sandbox Code Playgroud)

是否有隐式创建的任何方式q4Quota使用加法运算符如下对象...

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

而不是诉诸......

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

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

Dan*_*Dan 36

据我所知,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)
}
Run Code Online (Sandbox Code Playgroud)

并使用它像:

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

var combined = NumClass.createFromObjects(n1, n2, n3);
Run Code Online (Sandbox Code Playgroud)

  • http://www.2ality.com/2011/12/fake-operator-overloading.html 更好。 (3认同)

Jus*_*ove 20

很不幸的是,不行.

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

var q4 = q1.plus(p2).plus(q3);
Run Code Online (Sandbox Code Playgroud)

  • 如果您的环境支持它,您还可以使用currying来获得更漂亮的API:`one(two)(three)` (5认同)
  • @elliottcable良好+聪明的思考,但虽然这可能适用于乘法,但即便如此,我认为它在典型的程序员心态中并不能很好地传达.我仍然会选择`一次(两次).(三次);`. (4认同)

Jay*_*Jay 14

由于每个人都投了我的另一个答案,我想发布概念代码的证明,其实际上按预期工作.

这已在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;
Run Code Online (Sandbox Code Playgroud)

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

  • Jay,你能说明一下如何使用MyNumber类进行算术运算(做一个例子)吗? (6认同)

Jus*_*ove 7

第二个建议:

var q4 = Quota.add(q1, q2, q3);
Run Code Online (Sandbox Code Playgroud)


B T*_*B T 5

我最近发现了这篇文章:http://www.2ality.com/2011/12/fake-operator-overloading.html.

它描述了如何在对象上重新定义valueOf方法,以便在javascript中执行类似运算符重载的操作.看起来你只能对正在操作的对象执行mutator操作,所以它不会做你想要的.尽管如此,它很有趣.


小智 5

您可以将对象隐式转换为整数或字符串。

仅当JavaScript需要数字或字符串时,才隐式转换对象。在前一种情况下,转换过程分为三个步骤:

1.-致电valueOf()。如果结果是原始的(不是对象),则使用它并将其转换为数字。

2.-否则,请致电toString()。如果结果是原始的,请使用它并将其转换为数字。

3.-否则,抛出一个TypeError。步骤1的示例:

3 * { valueOf: function () { return 5 } }

如果JavaScript转换为字符串,则会交换步骤1和2:首先尝试toString(),然后尝试valueOf()。

http://www.2ality.com/2013/04/quirk-implicit-conversion.html


Izh*_*aki 5

Paper.js做到了这一点,例如,通过加点(docs):

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

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

  • 此代码段使用提供的自定义解析器进行解释 - 这不是标准的 javascript。 (2认同)

Stu*_*ffe 5

我制作了一个在 JavaScript 中执行运算符重载的脚本。工作并不容易,所以有一些怪癖。我将从项目页面在这里交叉发布警告,否则您可以在底部找到链接:

  • 计算结果必须传递给新对象,因此您必须执行 new point(p1 + p2 + p3) 而不是 (p1 + p2 + p3),(假设您的用户定义对象名为“point”)。

  • 仅支持 +、-、* 和 /,不支持第五个算术运算符 %。对字符串的强制转换 (""+p1) 和比较 (p1 == p2) 不会按预期工作。如果需要,应该为这些目的构建新函数,例如 (p1.val == p2.val)。

  • 最后,计算答案所需的计算资源随项数呈二次方增加。因此,每个默认值在一个计算链中只允许 6 个项(尽管可以增加)。对于比这更长的计算链,将计算拆分,例如: new point(new point(p1 + p2 + p3 + p4 + p5 + p6) + new point(p7 + p8 + p9 + p10 + p11 + p12))

Github的页面