变量操作符是否可行?



是否有一种方法可以做到类似于以下任何一种:

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

不开箱。然而,在包括JS在内的许多语言中,手工构建很容易。

var operators = {
    '+': function(a, b) { return a + b },
    '<': function(a, b) { return a < b },
     // ...
};
var op = '+';
alert(operators[op](10, 20));

您可以使用基于ascii的名称,如plus,以避免在不需要时遍历字符串。然而,与此类似的问题中,有一半是因为有人用字符串表示操作符,并希望从中获得函数。

我们可以使用eval来实现这一点,因为我们正在使用它来进行操作符检查。

var number1 = 30;
var number2 = 40;
var operator = '===';
function evaluate(param1, param2, operator) {
  return eval(param1 + operator + param2);
}
if (evaluate(number1, number2, operator)) {}

我相信您需要一个变量操作符。这是一个,创建为对象。您可以通过以下命令更改当前操作:

[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

您可以使用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));

一个比较新的方法。使用curry可以很好地完成:

const calculate = a => str => b => {switch(str) {
  case '+': return a + b
  case '-': return a - b
  case '/': return a / b
  case '*': return a * b
  default: return 'Invalid operation'
}}
const res = calculate(15)('*')(28)
console.log('15 * 28 =', res)

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

从我最近发布的另一个答案来看,这是在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陷阱来拦截传入的值/防止覆盖。您可以将操作数和操作存储在一些中央查找中,并使用一个简单的方法将原始值跟踪到产生该值的操作,然后创建任何您想要的逻辑来执行自定义操作。另一种允许任意接收器稍后可以重构为复杂形式的方法是将数据编码为原始值,以便它可以逆转回您的复杂类。例如,3个不同的8位整数(255,255,255)的RGB值可以在接收端转换为单个数字,接收端可以简单地将其转换回其复杂组件。或者对于更复杂的数据,您甚至可以返回JSON序列化字符串。

使用Harmony代理(Firefox6+, Nodejs with flag)使整个过程变得非常容易,因为你可以在基本上所有事情上创建捕获代理,并从头到尾反省整个过程,做任何你想做的事情。您的数据/类的操作数实例,内部引擎可能访问的每个可能值的valueOf/toString/getter,您预先知道的任何接收器对象,甚至在with(trappingProxy){ "all variable lookup, creation, and setting in here invokes traps on our proxy"; }

的情况下捕获任意接收器

复制自puvox-library:

compare(a, b, operator) {
    if(operator === '==') return a == b;
    else if (operator === '===') return a === b;
    else if (operator === '!=') return a != b;
    else if (operator === '!==') return a !== b;
    else if (operator === '>') return a > b;
    else if (operator === '>=') return a >= b;
    else if (operator === '<') return a < b;
    else if (operator === '<=') return a <= b;
    else throw "Unknown operator";
},
calculate(a, b, operator) {
    if(operator === '+') return a + b;
    else if (operator === '-') return a - b;
    else if (operator === '*') return a * b;
    else if (operator === '/') return a / b;
    else if (operator === '%') return a % b;
    else throw "Unknown operator";
},

最新更新