我创建了一个用于以类似于Vue.js的方式切换CSS类的微库,基于针对某些状态评估的JavaScript字符串。
我有一个包含我要检查的变量的对象,想要覆盖一些基本的表达式,而不必使用一些外部包(我试过jexl
,expr-eval
但是它们很庞大和善良过时了。
对于非常简单的表达式,没有eval或其他库,是否有任何快速甚至是脏的方法来实现这一目标?
以下是一些例子:
const evaluate = (expr, state) => /* ? */
const state = {
isActive: true,
isRed: false,
count: 637
}
evaluate('isActive', state) // -> true
evaluate('!isRed', state) // -> true
evaluate('isRed == true', state) // -> false
evaluate('isActive && isRed', state) //-> false
evaluate('count > 100', state) // -> true
// ...
答案 0 :(得分:1)
为什么不使用箭头功能?:
const evaluate = (fn, state) => fn(state);
evaluate(s => s.isActive, state);
evaluate(s => !s.isRed, state);
或者,如果你真的想要评估一个字符串的坏方法:
const evaluate = (expr, state) => {
with(state) { eval(expr); }
};
答案 1 :(得分:0)
这个不能处理2个值的比较和单个值的评估 - 它也不能处理嵌套对象,但是你说你需要一个非常原始的对象,所以在这里你去:
const matchers = [
[/^\s*(!?\w+)\s*==\s*(!?\w+)\s*$/,
function(a, b) { return semieval(a, this) == semieval(b, this) }],
[/^\s*(!?\w+)\s*===\s*(!?\w+)\s*$/,
function(a, b) { return semieval(a, this) === semieval(b, this) }],
[/^\s*(!?\w+)\s*>=\s*(!?\w+)\s*$/,
function(a, b) { return semieval(a, this) >= semieval(b, this) }],
[/^\s*(!?\w+)\s*<=\s*(!?\w+)\s*$/,
function(a, b) { return semieval(a, this) <= semieval(b, this) }],
[/^\s*(!?\w+)\s*>\s*(!?\w+)\s*$/,
function(a, b) { return semieval(a, this) > semieval(b, this) }],
[/^\s*(!?\w+)\s*<\s*(!?\w+)\s*$/,
function(a, b) { return semieval(a, this) < semieval(b, this) }],
[/^\s*(!?\w+)\s*\|\|\s*(!?\w+)\s*$/,
function(a, b) { return semieval(a, this) || semieval(b, this) }],
[/^\s*(!?\w+)\s*&&\s*(!?\w+)\s*$/,
function(a, b) { return semieval(a, this) && semieval(b, this) }],
[/^\s*!(!?\w+)\s*$/,
function(a) { return !semieval(a, this) }],
[/^\s*true\s*$/,
function() { return true }],
[/^\s*false\s*$/,
function() { return false }],
[/^\s*([\d]+)\s*$/,
function(a) { return parseInt(a, 10) }],
[/^\s*(!?\w+)\s*$/,
function(a) { return this.hasOwnProperty(a) ? this[a] : a }]
];
function semieval(statement, object) {
for(let matcher of matchers) {
if(matcher[0].test(statement)) {
let parts = statement.match(matcher[0]);
return matcher[1].apply(object, parts.slice(1));
}
}
}
const state = {
isActive: true,
isRed: false,
count: 637
}
console.log(
semieval('isActive', state) // -> true
)
console.log(
semieval('!isRed', state) // -> true
)
console.log(
semieval('isRed == true', state) // -> false
)
console.log(
semieval('!!isRed', state) // -> false
)
console.log(
semieval('isActive && isRed', state) //-> false
)
console.log(
semieval('count > 100', state) // -> true
)
&#13;
这样做是将RegExp的语句与适合以下之一的语句进行比较:
a==b
,a===b
,a<=b
,a>=b
,a<b
,a>b
,a&&b
,a||b
,{{ 1}},!a
当找到匹配的模式时,它会尝试找出值a
,如果给定a
,则首先检查值是b
,{{}} {1}},一个数字 - 然后才检查传递的对象是否存在现有密钥并返回其值以进行比较。