web-dev-qa-db-fra.com

Des opérateurs variables sont-ils possibles?

Existe-t-il un moyen de faire quelque chose de similaire à l'une des opérations suivantes:

var1 = 10; var2 = 20;
var operator = "<";
console.log(var1 operator var2); // returns true

- OR -

var1 = 10; var2 = 20;
var operator = "+";
total = var1 operator var2; // total === 30
75
Gary

Pas hors de la boîte. Cependant, il est facile de construire à la main dans de nombreuses langues, y compris JS.

var operators = {
    '+': function(a, b) { return a + b },
    '<': function(a, b) { return a < b },
     // ...
};

var op = '+';
alert(operators[op](10, 20));

Vous pouvez utiliser des noms basés sur ascii comme plus, pour éviter de passer par des chaînes si vous n'en avez pas besoin. Cependant, la moitié des questions similaires à celle-ci ont été posées parce que quelqu'un avait des chaînes représentant les opérateurs et voulait des fonctions de leur part.

148
user395760

Je crois que vous voulez un opérateur variable. en voici un, créé comme objet. vous pouvez modifier l'opération en cours en modifiant:

[yourObjectName].operation = "<" //changes operation to less than


function VarOperator(op) { //you object containing your operator
    this.operation = op;

    this.evaluate = function evaluate(param1, param2) {
        switch(this.operation) {
            case "+":
                return param1 + param2;
            case "-":
                return param1 - param2;
            case "*":
                return param1 * param2;
            case "/":
                return param1 / param2;
            case "<":
                return param1 < param2;
            case ">":
                return param1 > param2;
        }
    }
}

//sample usage:
var vo = new VarOperator("+"); //initial operation: addition
vo.evaluate(21,5); // returns 26
vo.operation = "-" // new operation: subtraction
vo.evaluate(21,5); //returns 16
vo.operation = ">" //new operation: ">"
vo.evaluate(21,5); //returns true
6
danniel

Vous pouvez utiliser la fonction eval(), mais ce n'est pas une bonne idée. Je pense que la meilleure façon d'écrire des fonctions pour vos opérateurs comme ceci:

var addition = function(first, second) {
   return first+second;
};

var subtraction = function(first, second) {
   return first-second;
};

var operator = addition;

alert(operator(12, 13));

var operator = subtraction;

alert(operator(12, 13));
6
Manuel Richarz

nous pouvons l'implémenter en utilisant eval, car nous l'utilisons pour la vérification de l'opérateur.

var number1 = 30;
var number2 = 40;
var operator = "===";

function evaluate(param1, param2, operator) {
     return eval(param1 + operator + param2);
}

if(evaluate(number1, number2, operator)) {
}

de cette façon, nous pouvons utiliser l'évaluation dynamique de l'opérateur.

5
Manu

D'après une autre réponse que j'ai récemment publiée, c'est en V8 et je pense que JavaScriptCore, mais pas Firefox et ce n'est pas spec. Puisque vous pouvez intercepter l'opération et les comparateurs, vous pouvez implémenter une surcharge native de l'opérateur dans la plupart des situations avec un peu de travail.

var actions = [];
var overload = {
  valueOf: function(){
    var caller = arguments.callee.caller;
    actions.Push({
      operation: caller.name,
      left: caller.arguments[0] === this ? "unknown" : this,
      right: caller.arguments[0]
    });
    return Object.prototype.toString.call(this);
  }
};
overload.toString = overload.valueOf;
overload == 10;
overload === 10;
overload * 10;
10 / overload;
overload in window;
-overload;
+overload;
overload < 5;
overload > 5;
[][overload];
overload == overload;
console.log(actions);

Sortie:

[ { operation: 'EQUALS',
    left: overload,
    right: 10 },
  { operation: 'MUL',
    left: overload,
    right: 10 },
  { operation: 'DIV',
    left: 'unknown',
    right: overload },
  { operation: 'IN',
    left: overload,
    right: DOMWindow },
  { operation: 'UNARY_MINUS',
    left: overload,
    right: undefined },
  { operation: 'TO_NUMBER',
    left: overload,
    right: undefined },
  { operation: 'COMPARE',
    left: overload,
    right: 5 },
  { operation: 'COMPARE',
    left: 'unknown',
    right: overload },
  { operation: 'ToString',
    left: 'unknown',
    right: overload } ]

À ce stade, vous avez toutes les entrées et l'opération de sorte que la partie restante est le résultat de l'opération. Le destinataire de l'opération recevra une valeur primitive, soit une chaîne, soit un nombre, et vous ne pouvez pas empêcher cela. Si ce n'est pas un récepteur arbitraire, par exemple une instance de la classe que l'opérateur a surchargée, vous pouvez gérer divers pièges get/set pour intercepter la valeur entrante/empêcher l'écrasement. Vous pouvez stocker les opérandes et l'opération dans une recherche centrale et utiliser une méthode simple pour retracer une valeur primitive jusqu'à l'opération qui l'a produite, puis créer la logique que vous souhaitez effectuer votre opération personnalisée. Une autre méthode qui permettrait à des récepteurs arbitraires qui pourraient plus tard être reconstitués sous des formes complexes serait de coder les données dans la valeur primitive afin qu'elles puissent être inversées dans votre classe complexe. Comme par exemple, une valeur RVB de 3 entiers 8 bits distincts (255, 255, 255) pourrait être convertie en un seul nombre à l'extrémité get et l'extrémité récepteur pourrait la reconvertir trivialement en ses composants complexes. Ou pour des données plus complexes, vous pouvez même renvoyer une chaîne sérialisée JSON.

Avoir accès aux proxys Harmony (Firefox6 +, Nodejs avec indicateur) facilite énormément tout ce processus, car vous pouvez créer des proxys de piégeage sur pratiquement tout et introspecter l'ensemble du processus de bout en bout et faire ce que vous voulez. Les instances d'opérande de vos données/classe, la valeur de/toString/getters de toutes les valeurs possibles auxquelles le moteur interne peut accéder, tout objet récepteur dont vous avez une connaissance préalable, et même piéger des récepteurs arbitraires dans le cas de with(trappingProxy){ "all variable lookup, creation, and setting in here invokes traps on our proxy"; }

3
user748221

Vous ne pouvez pas surcharger les opérateurs en JavaScript. Vous pouvez bien sûr utiliser des fonctions pour aider

var plus = function(a, b) {
    return a + b;
};

var smaller = function(a, b) { 
    return a < b;
};

var operator = plus;
var total = operator(a, b);
operator = smaller;
if(operator(var1, var2)){ /*do something*/ }
2
cellcortex