76 votes

Surcharge des opérateurs arithmétiques en JavaScript ?

C'est la meilleure façon de formuler cette question, compte tenu de la définition de la "classe" 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;
    };
};

et le code de configuration de test suivant :

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"

Existe-t-il un moyen de créer implicitement q4 en tant que Quota en utilisant l'opérateur d'addition comme suit...

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

plutôt que de recourir à...

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

Si ce n'est pas le cas, quelles sont les meilleures pratiques recommandées dans ce domaine pour rendre les objets numériques JavaScript personnalisés composables via les opérateurs arithmétiques ?

0 votes

Jetez un coup d'œil à SweetJS qui peut faire exactement cela.

0 votes

0 votes

39voto

Dan Points 20968

Pour autant que je sache, Javascript (du moins tel qu'il existe actuellement) ne prend pas en charge la surcharge des opérateurs.

Le mieux que je puisse suggérer est une méthode de classe pour créer de nouveaux objets de quota à partir de plusieurs autres. Voici un exemple rapide de ce que je veux dire :

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

et l'utiliser comme :

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

var combined = NumClass.createFromObjects(n1, n2, n3);

3 votes

1 votes

Je suis un peu déçu qu'un langage qui renvoie des valeurs négatives à partir d'opérandes négatifs à son opérateur de modulation ne supporte pas la surcharge des opérateurs. À l'heure actuelle, tout le monde doit implémenter % comme ((a%b)+b)%b.

24voto

Justin Love Points 3073

Malheureusement non.

Pour les fallbacks, si vous avez organisé les valeurs de retour, vous pouvez utiliser le chaînage de méthodes.

var q4 = q1.plus(p2).plus(q3);

5 votes

Si votre environnement le permet, vous pouvez également utiliser le currying pour une API plus jolie : one(two)(three)

5 votes

@elliottcable Bonne+intelligence, mais si cela peut convenir pour la multiplication, même dans ce cas, je ne pense pas que cela communique bien dans l'esprit du programmeur typique. J'opterais toujours pour one.times(two).times(three); .

0 votes

En CoffeeScript, on peut aussi supprimer les parenthèses :)

16voto

Jay Points 1457

Puisque tout le monde a rejeté mon autre réponse, je voulais poster un code de preuve de concept qui fonctionne effectivement comme prévu.

Ceci a été testé dans chrome et 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;

Si quelqu'un avait l'amabilité de donner une explication technique pour expliquer pourquoi ce n'est pas suffisant, je serais heureux de l'entendre !

1 votes

Le passage au nouveau type dans le cast peut être remplacé si nécessaire par le dérivé .....

6 votes

Jay, pouvez-vous montrer comment cela fonctionnerait avec une classe MyNumber pour faire de l'arithmétique (faire un exemple) ?

0 votes

Cela fonctionne-t-il simplement parce que le type contient une seule valeur int ?

7voto

Justin Love Points 3073

Deuxième suggestion :

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

6voto

B T Points 4868

Je suis récemment tombé sur cet article : http://www.2ality.com/2011/12/fake-operator-overloading.html .

Il décrit comment vous pouvez redéfinir la méthode valueOf sur les objets pour faire quelque chose comme une surcharge d'opérateurs en javascript. Il semble que l'on ne puisse réellement effectuer des opérations de mutateur que sur les objets sur lesquels on opère, donc cela ne ferait pas ce que vous voulez. C'est néanmoins intéressant.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X