如何在一个作用域中执行JS代码的不同部分

How to execute different partsof the JS code in one scope

本文关键字:代码 JS 执行 同部 作用域 一个      更新时间:2023-09-26

我有几个脚本块相互依赖。我需要在一个作用域中执行它们。

我的尝试:

var scopeWrapper = {}; 
with(scopeWrapper) {
    (function() {
        this.run = function(code) {
            eval(code);
        };
    }).call(scopeWrapper);
}
scopeWrapper.run('function test() { alert("passed"); }');
scopeWrapper.run('test();');

我得到'test is not defined'错误。看起来代码是在不同的作用域中执行的。为什么会发生这种情况?

编辑: 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,并允许您共享上下文。

我很抱歉我之前的回答,我误解了规格,我希望这个答案能帮助你。

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


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

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

在你的例子中,应该是这样的:

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)求值,那么,如10.4.1.1所述,使用C语言的eval代码初始化执行上下文,就像它是一个全局执行上下文一样。

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

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都被单独求值。