javascript - 使用 eval 执行函数

标签 javascript

我不明白 eval 的工作原理。 假设我有一个函数 foo:

function foo() {
    console.log("test");
}

然后我写

eval("foo()");

eval("foo" + "();");

函数 foo 被执行,并且我打印出了“test”。 但是,如果我写:

eval("function foo() { console.log(\"foo\"); }();");

eval("function foo() { console.log(\"foo\"); }" + "();");

我收到“SyntaxError: Unexpected token )”。 这是为什么?我看到当我传递函数名称时,它会被计算到函数的代码中,所以我认为它应该与“eval(”foo”+“();”);”相同。

如果有什么不同的话,我正在使用 Chrome 27。

最佳答案

因为没有具体答案为什么最后一个片段失败,并且似乎没有人警告您eval的危险:

评估,根据MDN :

A string representing a JavaScript expression, statement, or sequence of statements. The expression can include variables and properties of existing objects.

你的字符串,“function foo(){console.log('foo');}()”实际上由2个语句组成,这对JS引擎来说毫无意义。嗯,第二个没有:

function foo(){console.log('foo');}//function declaration, fine
;//<-- js adds implied statement terminator
()//no invocation, because no function reference, group nothing ==> does not compute, raise error

这就是为什么您必须通过添加运算符将函数声明语句转换为表达式。通常,这是分组运算符:()

(function foo(){ console.log('foo')});

函数声明现在是一个表达式,所有内容(包括分组())都可以被视为一条语句,除非后面的代码属于上面的代码。在这种情况下,调用括号显然是这样做的,因此 JS 引擎会为您进行排序。
为了清楚起见,有人说首选符号是:

(function f(){}());//<-- invoking parentheses inside group

这是有道理的,因为毕竟调用是语句的一部分。

如果您不喜欢所有这些括号,任何运算符都可以:

~function(){}();//bitwise not
+function(){}();//coerce to number

都同等有效。请注意,它们更改函数表达式的可能返回值。

(function(){}());//resolves to undefined
+function(){}();//resolves to NaN, because undefined is NotANumber

那么,您的 eval 的外观可能是以下任意一种:

eval("(function (){console.log('foo');}());");
eval("~function (){console.log('foo');}();");
eval("!function (){console.log('foo');}();");

等等,等等......

最后,eval 在全局范围内计算代码,因此任何包含函数 eval 的代码都可能并且很可能会污染全局命名空间。恶意代码还可以访问一切,因此请警惕 XSS 攻击和所有其他基于 JS 的技术。
底线是,eval邪恶,特别是因为所有浏览器现在都原生支持JSON.parse,而对于那些不支持的浏览器,仍然有一个经过尝试和测试的 JSON2.js 文件。
在严格模式下使用 eval 确实使事情变得更安全,但根本无法防止 XSS 攻击,例如,代码仍然可以操作 DOM,并重新分配暴露的 DOM 引用或对象。

如果您想了解更多信息,请搜索“为什么 eval 是邪恶的”。
另外check the ECMAScript specs

关于javascript - 使用 eval 执行函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17447256/

相关文章:

javascript - winston : How to get logging with timestamp at the front

javascript - Vue 自定义元素与 vee-validate ValidationObserver 组件发生错误

Javascript 对象属性名称

javascript - 如何创建/打印用户定义的(输入)数组,在 for-each 函数中对输入没有限制

javascript - 如何在javascript中检查文件是否存在?

javascript - 为什么 const 通过扩展运算符更新属性?

javascript - 在 Javascript 中使用用户指定的参数作为键

javascript - 光标在 WKWebView 中的位置,在 iOS 中有一个可编辑的段落

javascript - 如何使用preloadjs优先加载资源?

javascript - 如何防止或停止父组件在 vuejs 中重新渲染