Les opérateurs variables sont-ils possibles?

89

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

-- OU --

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

Réponses:

175

Pas hors de la boîte. Cependant, il est facile de créer à la main dans de nombreux langages, 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 des opérateurs et voulait des fonctions de leur part.


la source
6

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
Danniel
la source
6

Vous pouvez utiliser la eval()fonction, 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 celle-ci:

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));
Manuel Richarz
la source
6

nous pouvons l'implémenter en utilisant eval, puisque nous l'utilisons pour la vérification des opérateurs.

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 manière, nous pouvons utiliser l'évaluation dynamique des opérateurs.

Manu
la source
3

D'après une autre réponse que j'ai récemment publiée, c'est dans V8 et je pense que JavaScriptCore, mais pas Firefox et ce n'est pas des spécifications. Comme 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);

Production:

[ { 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, donc la partie restante est le résultat de l'opération. Le récepteur de l'opération obtiendra 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, disons une instance de la classe que vous avez surchargée par l'opérateur, vous pouvez gérer diverses interruptions 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 de votre choix pour votre opération personnalisée. Une autre méthode qui autoriserait des récepteurs arbitraires qui pourraient plus tard être reconstitués sous des formes complexes consisterait à coder les données dans la valeur primitive afin qu'elles puissent être inversées dans votre classe complexe. Comme disons, une valeur RVB de 3 entiers 8 bits distincts (255, 255, 255) pourrait être convertie en un seul nombre à la fin et le récepteur pourrait la reconvertir 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 à Harmony Proxies (Firefox6 +, Nodejs avec indicateur) facilite énormément tout ce processus, car vous pouvez créer des proxies 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, les valueOf / toString / getters de toutes les valeurs possibles auxquelles le moteur interne peut accéder, tout objet récepteur dont vous avez une pré-connaissance, et même intercepter des récepteurs arbitraires dans le cas dewith(trappingProxy){ "all variable lookup, creation, and setting in here invokes traps on our proxy"; }


la source
2

Vous ne pouvez pas surcharger les opérateurs dans 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*/ }
cellcortex
la source