Возможны ли переменные операторы? - PullRequest
73 голосов
/ 29 апреля 2011

Есть ли способ сделать что-то похожее на одно из следующих:

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

- ИЛИ -

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

Ответы [ 6 ]

145 голосов
/ 29 апреля 2011

Не из коробки. Однако его легко собрать вручную на многих языках, включая JS.

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

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

Вы можете использовать имена на основе ascii, например, plus, чтобы избежать просмотра строк, если вам это не нужно. Однако половина вопросов, подобных этому, была задана, потому что у кого-то были строки, представляющие операторы, и они хотели получить от них функции.

6 голосов
/ 29 апреля 2011

Полагаю, вам нужен оператор переменной. вот один, созданный как объект. Вы можете изменить текущую операцию, изменив:

[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 голосов
/ 29 апреля 2011

Вы можете использовать функцию eval(), но это не очень хорошая идея.Я думаю, что лучше написать такие функции для ваших операторов:

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));
5 голосов
/ 29 мая 2014

мы можем реализовать это с помощью eval, так как мы используем его для проверки операторов.

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

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

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

таким образом мы можем использовать динамическую оценку операторов.

3 голосов
/ 10 ноября 2011

Из другого ответа, который я недавно опубликовал, это в V8, и я думаю, что JavaScriptCore, но не Firefox, и это не спецификация.Поскольку вы можете перехватить операцию и компараторы, вы можете реализовать собственную перегрузку оператора в большинстве ситуаций с небольшим трудом.

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

Вывод:

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

На данный момент у вас есть всевходы и операции, поэтому оставшаяся часть является результатом операции.Получатель операции получит примитивное значение, либо строку, либо число, и вы не можете предотвратить это.Если это не произвольный получатель, скажем, экземпляр класса, который вы перегрузили оператором, вы можете обрабатывать различные ловушки get / set для перехвата входящего значения / предотвращения перезаписи.Вы можете сохранить операнды и операцию в некотором централизованном поиске и использовать простой метод, чтобы отследить примитивное значение до операции, которая его произвела, а затем создать любую логику, которую вы хотите выполнить в своей пользовательской операции.Другой метод, который позволит произвольным получателям, которые впоследствии могут быть преобразованы в сложные формы, заключался бы в кодировании данных в примитивное значение, чтобы их можно было вернуть обратно в ваш сложный класс.Например, значение RGB из 3 различных 8-битных целых чисел (255 255 255) может быть преобразовано в одно число на стороне получения, а сторона-получатель может просто преобразовать его обратно в сложные компоненты.Или для более сложных данных вы могли бы даже вернуть сериализованную строку JSON.

Наличие доступа к прокси-серверам Harmony (Firefox6 +, Nodejs с флагом) значительно упрощает весь этот процесс, поскольку вы можете создавать прокси-ловушки практически для всего и для самоанализавесь процесс от конца до конца и делай что хочешь.Экземпляры операндов ваших данных / класса, значения valueOf / toString / getters каждого возможного значения, к которому может обращаться внутренний механизм, любой объект-получатель, о котором вы предварительно осведомлены, и даже перехватывание произвольных получателей в случае with(trappingProxy){ "all variable lookup, creation, and setting in here invokes traps on our proxy"; }

2 голосов
/ 29 апреля 2011

Вы не можете перегружать операторы в JavaScript.Вы можете, конечно, использовать функции, чтобы помочь

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*/ }
...