Чи можливі змінні оператори?


89

Чи є спосіб зробити щось подібне до будь-якого з наступного:

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

Відповіді:


173

Не з коробки. Однак його легко створити вручну на багатьох мовах, включаючи 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

Я вважаю, що вам потрібен оператор змінної. ось один, створений як об’єкт. Ви можете змінити поточну операцію, змінивши:

[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

Ви можете використовувати 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));

6

ми можемо реалізувати це за допомогою 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

З іншої відповіді, яку я нещодавно розмістив, це у 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 555) може бути перетворено в одне число на кінці отримання, а кінець приймача може тривіально перетворити його назад у складні компоненти. Або для більш складних даних ви можете навіть повернути серіалізований рядок JSON.

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


2

Ви не можете перевантажувати оператори в 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*/ }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.