【问题标题】:What's wrong with `var myEval = eval; myEval("2+2")``var myEval = eval; 有什么问题?我的评估(“2+2”)`
【发布时间】:2015-05-08 06:48:41
【问题描述】:

根据MDN-EVAL

您不能通过 eval() 以外的名称调用 eval 函数来间接使用它;如果这样做,可能会发生运行时错误。例如,您不应该使用以下代码:

var x = 2; //1
var y = 4; //2
var myEval = eval; //3
eval("x + y"); //4
myEval("x + y"); //5

正常情况下,JavaScript 不会介意var someReference = someFunctionReference;,但是 eval 是特殊情况,所以我可以期待一些惊喜。

现在让我们看看下面的一些非严格模式下的运行

  1. Firefox/Aurora(V39.0) 不介意,上面的代码运行良好。
  2. Chrome(V 42.0.2311.135 m) 和 V8 4.2.77.18 运行良好。 (V8 版本取自 chrome://version/)
  3. Node(V0.10.35) 与 V8 3.14.5.9 抱怨错误 x 在第 5 行未定义 (V8 版本取自节点 -e "console.log(process.versions.v8)")

现在我的问题是为什么会有不同的行为,以及这种编码风格如何/何时会给我的程序带来风险。

P.S.://4 行在任何运行中都不会抱怨任何错误而且我在上面运行中的假设是 chrome/firefox 控制台在非严格模式下运行。

【问题讨论】:

  • 可能是出于某种形式的安全原因。但是您是否尝试过在 Node 中使用 eval("x + y") 来查看引用 eval 是否与您的问题或红鲱鱼有关?
  • eval//4 行在任何运行中都不会出错
  • 这句话来自 MDN 坦率地说是垃圾;它可能是几年前的遗留物,在间接eval 的行为建立之前。 MDN 是一个社区编辑的站点。虽然质量通常非常高,但有时你会得到一些奇怪的东西。这是其中之一。间接eval 有很多完全有效的用法。我要去修了……
  • 修正了 MDN 文章。
  • 是的...我可以看到更新...非常感谢 :)

标签: javascript eval


【解决方案1】:

eval 很特别。从 ES5 (~2009) 开始,对 eval 的直接调用在当前范围内有效,但对它的 间接 调用与 myEval 一样在全局范围内有效。这在§10.4.2§15.1.2.1.1 中有详细说明。

因此,如果您的代码在函数中运行,例如:

function foo() {
    var x = 2;
    var y = 4;
    var myEval = eval;
    myEval("x + y");
}

...那么正确 ES5 的行为将是抱怨x 不存在。

如果您的代码在所有函数之外的全局范围内,例如:

var x = 2;
var y = 4;
var myEval = eval;
myEval("x + y");

...那么正确的行为是得到结果6。完整示例如下。

现在我的问题是为什么会有不同的行为......

如果您在浏览器控制台中运行该代码,则可能取决于控制台实现(例如,一个控制台可能会在函数内评估您的代码,而另一个控制台可能会在全局范围内评估您的代码)。控制台是一个特殊的环境,像这样与范围相关的东西最好用普通页面进行测试。

以及如何/何时使用这种编码风格给我的程序带来风险。

直接或间接使用eval风险没有显着差异。风险来自在您无法控制的输入上使用eval(完全)。如果您从用户那里获取输入并立即在他们的计算机上运行它,那么风险主要在于他们。但是,如果您从一个用户那里获取输入,然后通过eval另一个 用户的计算机或您的服务器上运行该输入,这是一个重大风险:您允许该用户联系并在不属于他们的机器上运行代码。

P.S.:我在上面的假设运行 chrome/firefox 控制台在非严格模式下运行。

严格模式不会影响eval 的这一方面。 (它确实影响它的其他方面,特别是它是否可以在本地范围内创建变量[它可以在松散模式下,它不能在严格模式下];这也在 §10.4.2 .)


实例:

function direct() {
  var x = 2;
  var y = 4;
  return eval("x + y");
}

function indirect() {
  var x = 2;
  var y = 4;
  var myEval = eval;
  return myEval("x + y");
}

snippet.log("Direct (within function):");
try {
  snippet.log("Got " + direct());
}
catch (e) {
  snippet.log("Got exception: " + e.message);
}

snippet.log("Indirect (within function):");
try {
  snippet.log("Got " + indirect());
}
catch (e) {
  snippet.log("Got exception: " + e.message);
}

var globalX = 2;
var globalY = 4;

snippet.log("Direct (at global scope):");
try {
  snippet.log("Got " + eval("globalX + globalY"));
}
catch (e) {
  snippet.log("Got exception: " + e.message);
}

snippet.log("Indirect (at global scope):");
var myGlobalEval = eval;
try {
  snippet.log("Got " + myGlobalEval("globalX + globalY"));
}
catch (e) {
  snippet.log("Got exception: " + e.message);
}
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

正确的行为是显示:

直接(函数内): 有 6 个 间接(函数内): 出现异常:x 未定义 直接(在全球范围内): 有 6 个 间接(在全球范围内): 有 6 个

【讨论】:

  • 清楚地解释了我的问题......直接来自原产地的很好的参考......我希望我能两次支持这个答案:)谢谢;)
猜你喜欢
  • 1970-01-01
  • 2019-06-21
  • 2015-12-23
  • 2020-12-11
  • 2018-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多