我有一个包含一些条件的字符串,例如:
var str = "this.demoModel.active == '1' && this.demoModel.span > 5 || ..."
是否有一种直接的方式在javascript中解析它们,以便它们像一组条件一样工作。类似的东西:
if (JSON.parse(str) {})
。 ??
答案 0 :(得分:7)
有,但使用它们通常是最后的手段:eval
和Function
构造函数。 eval
在调用eval
的上下文中从字符串输入运行代码。 Function
构造函数从字符串创建函数。当然,在这两种情况下,这意味着您必须信任字符串的来源,因为它可以包含任意代码,并且您很乐意在代码的上下文中运行它。例如,你不会从用户A拿一个字符串,然后在用户B的浏览器中运行它 - 这将使用户B对用户A的攻击敞开大门。(对于“浏览器”替代“会话”或其他什么,问题就像在Node这样的环境中一样真实 - 或许更多 - 服务器端,因为它在brwoser中是客户端的。)
如果你接受用户的字符串并在他们自己的浏览器/会话/上下文中运行它,那很好。
以下是一个例子:
function Foo() {
this.demoModel = {
active: "1",
span: 7
};
}
Foo.prototype.run = function(str) {
if (eval(str)) {
console.log("Yes");
} else {
console.log("No");
}
};
var f = new Foo();
f.run("this.demoModel.active == '1' && this.demoModel.span > 5");
f.run("this.demoModel.active == '0' && this.demoModel.span < 5");
您还可以使用Function
构造函数,然后使用正确的this
调用它:
function Foo() {
this.demoModel = {
active: "1",
span: 7
};
}
Foo.prototype.run = function(str) {
var testfunc = new Function("return " + str);
if (testfunc.call(this)) {
console.log("Yes");
} else {
console.log("No");
}
};
var f = new Foo();
f.run("this.demoModel.active == '1' && this.demoModel.span > 5");
f.run("this.demoModel.active == '0' && this.demoModel.span < 5");
如果您 执行此操作,请尽可能选择Function
构造函数到eval
,因为它无法访问您使用它的范围内的所有内容,但它们都是你需要警惕的强大工具。
答案 1 :(得分:5)
您可以使用&#39; eval&#39;或者&#39;功能&#39;但正如所述on MDN
不要不必要地使用eval! - eval()是一个危险的函数,它执行它以调用者的特权传递的代码。如果您使用可能受恶意方影响的字符串运行eval(),您最终可能会使用您的网页/扩展程序的权限在用户的计算机上运行恶意代码。更重要的是,第三方代码可以看到调用eval()的范围,这可能会导致类似函数不易受影响的攻击。</ p>
if(new Function("CONDITON_STRING")()){
//Answer
};
答案 2 :(得分:5)
一般情况下,您应该尽量避免陷入这种情况:如果可能的话,应该避免将JavaScript存储在字符串中以供以后评估。根据您的实际情况,您可以考虑以下选项:
它们在实际使用中受到限制,因为它们与使用它们的脚本一起解析,但是they are also safe:
var str = `${this.demoModel.active == '1' && this.demoModel.span > 5}`;
分配此字符串后,它会立即评估其中的${ }
部分。
因此,如果评估可以立即进行,这只是一种解决方案,因为您无法将其存储在字符串中,然后期望稍后触发评估。
因此与以下内容没有太大区别:
var bool = this.demoModel.active == '1' && this.demoModel.span > 5;
解决方法可能是定义一个评估模板文字或表达式的函数,如下所示:
var rule = function() {
return this.demoModel.active == '1' && this.demoModel.span > 5;
};
...你可以传递该函数,例如作为回调:
doSomething(rule);
...然后 doSomething 可以这样调用它,绑定上下文,以便this
具有适当的值:
function doSomething(rule) {
if (rule.call(this)) console.log('rule passed');
}
另一个选择是为表达式创建一个对象结构,例如:
var rules = [
[{ // AND conditions:
"field": "active",
"compare": "eq",
"target": 1
}, {
"field": "span",
"compare": "gt",
"target": 5
}], // Next array will be OR'ed
[{
"field": "...."
"compare": "..",
"target": ...
}]
}];
这是一个嵌套数组,其中顶级将具有必须一起“或”的规则,而内部级别将被“和”在一起。
然后编写一个处理此结构的函数。 比较名称可以映射到代码中的函数,如下所示:
const comparators = {
"eq": (a, b) = a === b,
"gt": (a, b) = a > b
};
因此,要评估 rules 数组中的一个对象,可以使用:
execute: (obj) => comparators[this.demoModel[obj.compare]] // get the function
(this.demoModel[obj.field], obj.target) // pass arguments
此规则结构可以轻松保存并作为JSON字符串加载。
答案 3 :(得分:2)
尝试以下方法:
var str = 'true && true';
var str2 = 'true && false';
function strEval(fn) {
return new Function('return ' + fn)();
}
var conditionTrue = strEval(str);
var conditionFalse = strEval(str2)
if(conditionTrue)
{
console.log(conditionTrue)
}
if(!conditionFalse)
{
console.log(conditionFalse)
}
答案 4 :(得分:-1)
使用eval方法将字符串转换为命令。
var cond = 'd === 1';
var d = 0;
if (eval(cond)) { console.log('1'); } else { console.log('2'); } // output: 2
d = 1;
if (eval(cond)) { console.log('1'); } else { console.log('2'); } // output: 1