【问题标题】:How to execute different partsof the JS code in one scope如何在一个范围内执行 JS 代码的不同部分
【发布时间】:2013-03-14 12:44:25
【问题描述】:

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

我的尝试:

var scopeWrapper = {}; 

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

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

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

【问题讨论】:

  • 你为什么要这样做呢?
  • @epascarello 阅读代码,他正在制作脚本运行器...
  • @BenjaminGruenbaum,我知道,我想知道为什么,而不是它的作用。

标签: javascript scope


【解决方案1】:

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

虽然我自己在 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)");

(here is this code in action)

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

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

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


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

考虑使用Function constructor,然后.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()")

这里直接引用from the spec:

如果没有调用上下文或者 eval 代码不是通过直接调用 (15.1.2.1.1) 来评估 eval 函数,那么, 如 10.4.1.1 中所述,使用 C 的 eval 代码将执行上下文初始化为全局执行上下文。

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

【讨论】:

  • 我喜欢这个想法 (+1),但它认为值得注意的是,真正的“scopeWrapper”是在共享 context 中执行所有内容,而不是在共享 scope 。请注意,如果您将 this.test = func... 替换为 var test = func...,它将不起作用(与它实际上是相同的范围不同)。
  • 我认为Function 构造函数没有任何帮助,函数的作用域也消失了——它不适用于run('function test() { alert("passed"); }')。您的分配代码也适用于eval
  • @Bergi 查看编辑。如果您有时间,我想听听您的意见。
  • 感谢您修复它。使用 iframe 的全局范围的想法很好:-)
【解决方案2】:

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 都会被单独评估。

【讨论】:

  • 他正在设置 this.run 。此外,问题在于决定 eval 上下文的方式(请参阅我的回答),而不是定义 run 的范围......
  • 我的意思是“在this.run内部”。
猜你喜欢
  • 2020-06-14
  • 1970-01-01
  • 1970-01-01
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多