Are Variable Operators Possible?

2019-01-02 15:33发布

Is there a way to do something similar to either of the following:

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

6条回答
怪性笑人.
2楼-- · 2019-01-02 15:47

From another answer I recently posted, this is in V8 and I think JavaScriptCore, but not Firefox and it's not spec. Since you can trap the operation and the comparators you can implement operator native overloading in most situations with a bit of work.

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

Output:

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

At this point you have all the inputs and the operation so the remaining part is the result of the operation. The receiver of the operation will get a primitive value, either string or number, and you can't prevent this. If it's not an arbitrary reciever, say an instance of the class you've operator overloaded, you can handle various get/set traps to intercept the incoming value/prevent overwriting. You can store the operands and operation in some central lookup and use a simple method to trace a primitive value back to the operation which produced it, and then create whatever logic you want to do your custom operation. Another method which would allow arbitrary receivers which could later be reconstituted into complex forms would be in encoding the data into the primitive value so that it can be reversed back into your complex class. Like say an RGB value of 3 distinct 8bit integers (255,255,255) could be be converted into a single number on the get end and the receiver end could trivial convert it back into its complex components. Or for more complex data you could even return a JSON serialized string.

Having access to Harmony Proxies (Firefox6+, Nodejs with flag) makes this whole process immensely easier, as you can create trapping proxies on basically everything and introspect the entire process from end to end and do whatever you want. The operand instances of your data/class, the valueOf/toString/getters of every possible value the internal engine may access, any receiver object you have pre-awareness of, and even trap arbitrary receivers in the case of with(trappingProxy){ "all variable lookup, creation, and setting in here invokes traps on our proxy"; }

查看更多
唯独是你
3楼-- · 2019-01-02 15:48

we can implement this using eval, since we are using it for operator checking.

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

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

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

in this way we can use dynamic operator evaluation.

查看更多
孤独寂梦人
4楼-- · 2019-01-02 15:57

Not out of the box. However, it's easy to build by hand in many languages including JS.

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

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

You can use ascii-based names like plus, to avoid going through strings if you don't need to. However, half of the questions similar to this one were asked because someone had strings representing operators and wanted functions from them.

查看更多
无与为乐者.
5楼-- · 2019-01-02 16:03

You can't overload operators in JavaScript. You can off course use functions to help

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*/ }
查看更多
唯独是你
6楼-- · 2019-01-02 16:05

You can use the eval() function, but that is not a good idea. I think the better way is writing functions for your operators like this:

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));
查看更多
永恒的永恒
7楼-- · 2019-01-02 16:10

I believe you want a variable operator. here's one, created as object. you can change the current operation by changing:

[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
查看更多
登录 后发表回答