5

在过去的几天里,我一直在构建一个基本的实时评估 JavaScript 开发环境(我称之为WEPL。),并意识到能够将错误消息与行号相关联会很好。不幸的是, eval() 没有提供一个很好的方法来做到这一点,我可以找到。

到目前为止我提出的解决方案是在 eval() 之前转换源代码,以便它是对 eval() 的包装器的一组嵌套调用,它在 eval 之前记录一些信息,检查 eval 是否成功,以及然后使用该信息向用户输出更有用的故障排除信息。

我的问题是,为什么这可能是个坏主意?我需要解决哪些问题才能确保它运作良好?

我的意思是这种转变的一个例子,只是为了具体化。

这个

if (cond) {
  return foo + bar;
}
else {
  return baz + quux;
}

变成这个

if (myEval('cond')) {
  return myEval("myEval(\"foo\") + myEval(\"bar\")");
else {
  return myEval("myEval(\"baz\") + myEval(\"quux\")");
}

尽管我可以做到,但我显然没有包装最高级别,而程序化版本会。

4

2 回答 2

3

如果您想接受甚至是远程复杂的脚本,这将不起作用。几个潜在的问题:

范围

var i = 1; // global scope
!function() {
    var i = 2; // function scope
}();
alert(i); // 1

对比

myEval('var i = 1;'); // global scope
myEval('!function() {
    myEval(\'var i = 2;\'); // eval has global scope, always
}();');
myEval('alert(i);'); // 2

闭包

!function() {
    var i = 1; // local to outer function
    !function() { // inherits context from outer function
        alert(i); // 1
    }();
}();

对比

myEval('!function() {
    myEval(\'var i = 1;\'); // local to outer function
    myEval(\'!function() { // eval has global scope; myEval inherits from wherever it was defined
        myEval(\\\'alert(i);\\\'); // undefined
    }();\');
}();');

这个

var obj = {
    n: 1,
    f: function() {
        return this.n; // this is the object f is called from
    }
}
alert(obj.f()); // 1

对比

myEval('var obj = {
    n: myEval(\'1\'),
    f: myEval(\'function() {
           return myEval(\\\'this.n\\\'); // this is always the window in eval
       }')
}');
myEval('alert(obj.f());'); // undefined

逃脱蠕变

你需要转义每一个引用,你也需要转义转义符号。在包含大量对象、闭包、内部函数等的代码中,这将导致转义符号变得难以管理:

!function() {
    $(function() {
        $('#foo').click(function() {
            setTimeout(function() {
                $.post('/', function(res) {
                     log(res);
                });
            }, 1000);
        });
    });
}();

(请注意,这不是一个特别人为或复杂的示例,它仅涉及在某个事件上触发回调的延迟动作)

myEval('!function() {
    myEval(\'$(myEval(\\\'function() {
        myEval(\\\\\\\'$(\\\\\\\'#foo\\\\\\\').click(myEval(\\\\\\\\\\\\\\\'function() {
            myEval(\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'setTimeout(myEval(\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'function() {
                myEval(\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'$.post('/', myEval(\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'function(res) {
                     myEval(\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'log(res);\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\');
                }\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'));\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\');
            }\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'), 1000);\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\');
        }\\\\\\\\\\\\\\\'));\\\\\\\');
    }\\\'));\');
}();');

你可能会看到我在说什么。

于 2012-09-16T20:39:02.563 回答
2

在为 IE 开发扩展时,我不得不做类似的事情。我最终创建了一个名为“lineNumber”的全局变量,并将代码转换为更像这样:

lineNumber = 1; if (cond) {
  lineNumber = 2; return foo + bar;
}
else {
  lineNumber = 5; return baz + quux;
}

当然,我确保我在所有块周围都使用了花括号,并且必须保持我的编码足够简单以避免混淆我可怜的蹩脚解析器——但它让我通过了它。

于 2012-09-14T20:48:53.587 回答