有没有办法做类似于以下任何一项的事情:
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
有没有办法做类似于以下任何一项的事情:
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
不是开箱即用。但是,使用包括 JS 在内的多种语言手动构建很容易。
var operators = {
'+': function(a, b) { return a + b },
'<': function(a, b) { return a < b },
// ...
};
var op = '+';
alert(operators[op](10, 20));
plus
如果不需要,您可以使用基于 ascii 的名称,例如, 以避免遍历字符串。然而,有一半的问题与这个问题相似,因为有人有代表运算符的字符串并想要从它们那里得到函数。
我相信你想要一个变量运算符。这是一个,创建为对象。您可以通过更改来更改当前操作:
[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 number1 = 30;
var number2 = 40;
var operator = '===';
function evaluate(param1, param2, operator) {
return eval(param1 + operator + param2);
}
if (evaluate(number1, number2, operator)) {}
这样我们就可以使用动态算子评估。
您可以使用该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));
您不能在 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)使整个过程变得非常容易,因为您可以在基本上所有内容上创建陷阱代理,并从头到尾自省整个过程并做任何您想做的事情。您的数据/类的操作数实例、内部引擎可能访问的每个可能值的 valueOf/toString/getters、您预先知道的任何接收器对象,甚至在以下情况下捕获任意接收器with(trappingProxy){ "all variable lookup, creation, and setting in here invokes traps on our proxy"; }
一种较新的方法。使用柯里化可以做得相当不错:
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)