Czy operatory zmienne są możliwe?


89

Czy istnieje sposób na zrobienie czegoś podobnego do jednego z poniższych:

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

- LUB -

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

Odpowiedzi:


174

Nie po wyjęciu z pudełka. Jednak można go łatwo zbudować ręcznie w wielu językach, w tym w JS.

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

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

Możesz używać nazw opartych na ascii, takich jak plus, aby uniknąć przechodzenia przez łańcuchy, jeśli nie musisz. Jednak połowa pytań podobnych do tego została zadana, ponieważ ktoś miał ciągi reprezentujące operatory i chciał od nich funkcje.


6

Myślę, że potrzebujesz operatora zmiennej. oto jeden, stworzony jako obiekt. możesz zmienić bieżącą operację zmieniając:

[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

Możesz użyć tej eval()funkcji, ale to nie jest dobry pomysł. Myślę, że lepszym sposobem jest pisanie funkcji dla operatorów w ten sposób:

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

możemy to zaimplementować używając eval, ponieważ używamy go do sprawdzania operatora.

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

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

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

w ten sposób możemy wykorzystać dynamiczną ocenę operatora.


3

Z innej odpowiedzi, którą niedawno opublikowałem, jest to wersja 8 i myślę, że JavaScriptCore, ale nie Firefox i nie jest to specyfikacja. Ponieważ możesz przechwytywać operację i komparatory, możesz zaimplementować natywne przeciążanie operatora w większości sytuacji przy odrobinie pracy.

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);

Wynik:

[ { 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 } ]

W tym momencie masz wszystkie dane wejściowe i operację, więc pozostała część jest wynikiem operacji. Odbiorca operacji otrzyma wartość pierwotną, ciąg lub liczbę, i nie można temu zapobiec. Jeśli nie jest to dowolny odbiorca, powiedzmy instancja klasy, którą przeciążasz operator, możesz obsługiwać różne pułapki pobierania / ustawiania, aby przechwycić przychodzącą wartość / zapobiec nadpisaniu. Możesz przechowywać operandy i operacje w jakimś centralnym wyszukiwaniu i użyć prostej metody, aby prześledzić pierwotną wartość z powrotem do operacji, która ją wygenerowała, a następnie utworzyć dowolną logikę, którą chcesz wykonać niestandardową operację. Inną metodą, która pozwoliłaby na dowolne odbiorniki, które można później odtworzyć w złożone formy, byłoby zakodowanie danych do wartości pierwotnej, aby można je było przywrócić z powrotem do klasy złożonej. Na przykład wartość RGB 3 różnych 8-bitowych liczb całkowitych (255,255,255) może zostać przekonwertowana na pojedynczą liczbę na końcu pobierania, a koniec odbiornika może trywialnie przekształcić ją z powrotem w złożone elementy. Lub w przypadku bardziej złożonych danych możesz nawet zwrócić serializowany ciąg JSON.

Dostęp do serwerów proxy Harmony (Firefox6 +, Nodejs z flagą) sprawia, że ​​cały ten proces jest znacznie łatwiejszy, ponieważ możesz tworzyć proxy pułapki w zasadzie na wszystkim i przeglądać cały proces od końca do końca i robić, co chcesz. Instancje operandów danych / klasy, valueOf / toString / getters każdej możliwej wartości, do której silnik wewnętrzny może uzyskać dostęp, dowolnego obiektu odbiornika, o którym masz wcześniejszą świadomość, a nawet pułapki arbitralnewith(trappingProxy){ "all variable lookup, creation, and setting in here invokes traps on our proxy"; }


2

Nie możesz przeciążać operatorów w JavaScript. Możesz oczywiście skorzystać z funkcji, które pomogą

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*/ }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.