3

我有几个脚本块相互依赖。我需要在一个范围内执行它们。

我的尝试:

var scopeWrapper = {}; 

with(scopeWrapper) {
    (function() {
        this.run = function(code) {
            eval(code);
        };
    }).call(scopeWrapper);
}

scopeWrapper.run('function test() { alert("passed"); }');
scopeWrapper.run('test();');

我收到“未定义测试”错误。似乎代码是在不同的范围内执行的。为什么会这样?

4

2 回答 2

8

编辑: Bergi指出我原来的答案是错误的,他是正确的。由于eval在其自己的范围内运行,并且函数构造函数仍然根据规范在函数范围内运行,这两者都不可能。

虽然我自己用 node.js 做了几次这样的事情,使用的vm模块可以让你更精细地控制代码的执行位置,但似乎浏览器需要不同的方法。

以这种方式共享变量的唯一方法是在 JavaScript 执行的全局范围内(可能在 iframe 中)这样做。你可以做到这一点的一种方法是脚本标签注入。

function run(code){
    var sc = document.createElement("script");
    sc.setAttribute("type","text/javascript");
    sc.innerHTML = code;
    document.body.appendChild(sc);
}

run("var x = 5");
run("document.write(x)");

这里是这个代码在行动

至于范围包装器,而不是将它们注入到同一帧中,而是将它们注入另一个iframe. 这会将他们的窗口对象范围限定为该 iframe,并允许您共享上下文。

我为我之前的回答谦虚地道歉,我误读了规范。我希望这个答案对你有所帮助。

我将之前的答案留在这里,因为我仍然相信它提供了一些关于构造函数如何工作eval的见解Function


在非严格模式下运行代码时,eval在页面的当前上下文中运行函数声明完成后,它声明的范围会消失,函数也会随之消失。

考虑使用Function 构造函数,然后.calling 它

在你的情况下,这将是这样的:

var scopeWrapper = {}; 
scopeWrapper.run = function(code){
    var functionToRun = new Function(code);
    functionToRun.call(scopeWrapper);
}
scopeWrapper.run('this.test = function() { alert("passed"); }');
scopeWrapper.run("this.test()")

这是直接来自规范的参考:

如果没有调用上下文或者如果 eval 代码没有通过对 eval 函数的直接调用 (15.1.2.1.1) 进行评估,则初始化执行上下文,就好像它是使用 eval 代码作为 C 的全局执行上下文一样如 10.4.1.1 中所述。

如果此代码在 node.js 中运行,请考虑使用vm模块。另请注意,这种方法仍然不安全,因为它允许您运行的代码更改您的代码。

于 2013-03-14T12:47:34.763 回答
0

test仅存在于this.run且仅在调用时:

// global scope
(function(){
  // local scope (equivalent of your "run" function scope)
  eval('function f(){};');
  console.log(f); // prints "function f(){}"
})();
console.log(f); // prints "ReferenceError: f is not defined"

每次调用run都会创建一个新的范围,其中每个code都单独评估。

于 2013-03-14T12:54:37.713 回答