我不明白 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/