使用 eval 将字符串转换为函数是否邪恶?

IT技术 javascript
2021-01-27 16:28:44

我听说过很多关于 eval() 的不同意见,并且有点不确定在这种情况下使用 eval() 是否可以:

假设我有一个这样的对象:

var bla = {
blubb: function (callback) {
       //GET some stuff via ajax
       //call the callback
    }
}

和这样的字符串:

 var someString = "bla.blubb";

为了调用函数(和回调)而对字符串求值是否是邪恶的?

var callMe = eval(someString)
callMe(function(){
   alert('yay')!
});
4个回答

我听说过很多关于 eval() 的不同意见

eval 不是一般的邪恶,有它的应用程序。

不确定在这种情况下是否可以使用 eval()

不,这是不行的。使用简单的括号符号成员运算符有一个更好的解决方案由于每天都会有人问这个问题,我可以在这里列出数百个被骗的人(只是前​​几个谷歌结果):

+1 这么多参考...
2021-03-14 16:28:44
这真的只是谷歌所有的结果都是有效的,虽然......
2021-03-25 16:28:44
感谢您对 eval 的清晰解释;)。感谢提供链接,我现在知道如何用英语表达(很难解释一个问题是法语:p)。
2021-04-03 16:28:44

让我们假设您的整个设计并不完全邪恶(但有一点点)。

这意味着您限制并指定您在someString. 例如,它可能是一个对象及其函数的路径,您可以在没有任何参数的情况下调用它(这使得它的危险性大大降低)并且带有上下文的全局对象。

然后很容易解析字符串并调用不带eval. 这样会更安全。例如 :

window.a = {b:{c:function(){console.log('here')}}};
var someString = "a.b.c";

var path = someString.split('.');
var f = window;
for (var i=0; i<path.length; i++) f = f[path[i]];
f.call(null);

一个改进是修复根对象(而不是窗口)以避免任何类型的调用。

许多欺骗者之一的链接可能比一遍又一遍地重写此片段更适合:-) 请参阅我的答案
2021-03-14 16:28:44
@Bergi 我不知道这是个骗子……对不起,这对我来说是第一次……
2021-03-15 16:28:44
当我输入我的评论时,你想出了同样的想法:) 对我来说绝对是最好的选择,你得到了我的投票!
2021-04-02 16:28:44
有这么多人问同样的问题,这有点令人担忧。这种耦合映射通常不是声音应用程序的基础......
2021-04-05 16:28:44

不要忘记,如果您知道对象的外观,您可以在 javascript 中使用“安全评估”。

在一个范围内:

this.foo = { bar:function(){return "baz"}};

// some code.
var obj = "foo";
var param = "bar";

this[obj][param](); // same as this.foo.bar();

除非您正在处理一些特定的事情(例如模板),否则您不需要使用 eval 来调用对象。

这就是哈希映射的工作原理,它只是一个键,而不是计算值。
2021-03-19 16:28:44
这不是“安全评估”,这只是一个成员运算符。
2021-03-20 16:28:44
尝试对数组执行 ["5"] ,这不仅仅是查找操作。
2021-03-25 16:28:44
这就是为什么我在表达式 "safe eval" 周围加上引号的原因,但它仍在评估字符串并查找对象的相关成员,对我来说听起来像是字符串评估。
2021-03-30 16:28:44
不。字符串没有被评估,这就是重点。这只是一个查找操作。
2021-04-11 16:28:44

它又是邪恶的,因为它很难调试。更好的方法是使用类似的东西:

function getValue(namespace, parent) {
    var parts = namespace.split('.'),
        current = parent || window;
    for (var i = 0; i < parts.length; i += 1) {
        if (current[parts[i]]) {
            current = current[parts[i]];
        } else {
          if (i >= parts.length - 1)
            return undefined;
        }
    }
    return current;
}
var foo = {
    bar: {
        baz: function () { alert('baz'); }
    }
};
var f = getValue('foo.bar.baz'); //true
if (typeof f === 'function') {
    f();
}

代码不止一个,eval('foo.bar.baz')但您可以弄清楚实际发生了什么,甚至可以使用断点对其进行调试。

如果我们谈论性能,这里有几个 jsperf 示例:

  1. http://jsperf.com/eval-vs-loop
  2. http://jsperf.com/eval-vs-loop/2