如何从堆栈顶部执行JS函数?

时间:2010-08-25 03:13:30

标签: javascript

我想从堆栈顶部执行一个函数。也就是说,任何用“var”定义的变量都应该在全局意义上定义。这可能吗? fn.call(窗口)不起作用。

<script>
  var foo = "I am top level foo.";

  var fn = function(){
    var foo = "Setting foo from in a function";
  }

  fn.call(window);  //doesn't work, var is still set locally in fn.
  alert(foo);  //desired effect will alert "setting foo from in a function"
</script>

请注意:我完全清楚,未指定“var”会使项目成为全局变量。问题是我无法指定“fn”的内容,它是用户定义的,但预计会从顶层运行。

如果有必要,我愿意使用eval。

4 个答案:

答案 0 :(得分:2)

我不确定你要做什么,但你不能用这种方式覆盖foo的价值。在全局上下文中指定var foo时,它将附加到全局对象(在全局范围内)。

当您在函数中指定var foo时,您在该函数的范围内声明了它。这意味着外界不知道 + 。你能做什么,是这样的:

var fn = function() {
   this.foo = "Setting foo from in a function";
};

或者更明确:

var fn = function() {
  window.foo = "Setting foo from in a function";
};

这是你想要的吗?

+ 当您在函数中定义foo时,它附加到激活对象而不是全局对象。每次输入函数的执行上下文时,都会创建一个新的激活对象。因此,每次调用该函数时,您都会获得一个新的foo。这也是一样,否则你将无法在函数范围内创建局部变量;他们会泄漏到全球范围内。

<强>更新

如果您真的想要在全局上下文中评估函数内部的代码,我想您可以执行以下操作。这很难看,我不确定你为什么要这样做,但是这里有:

var foo = 2;

var fn = function() {
   var foo = 3;
}

console.log(foo); //prints 2

var fnSource = fn.toSource();
eval(fnSource.replace(/^\(function\s*\(\)\s*{/, "").replace(/}\s*\)$/, ""));

console.log(foo); //prints 3

这将删除(function () {}),这样您最终只能使用中间的代码,然后通过eval运行。

我再次强调,我不建议这样做。

答案 1 :(得分:1)

你的问题太多了。局部变量就是:本地变量。它们在函数的本地范围内创建,不会在调用之外导出。作为调用者,您根本无法看到它们,因为它们不存储在您可以访问的任何类型的哈希或命名空间或对象中。

最好的办法是让用户修改他们的功能。

我想,除此之外,你可以跳过火环并对函数的toSource()源代码进行一些字符串搜索和替换,并删除var个关键字。或者点toSource(),删除function { ... }包装,然后eval()该代码。那可能有效。但这是一种过多的迂回,非常脆弱和主要的代码味道。


如果可以修改功能,那么解决方案很简单。如果你摆脱了var那么你将修改全局变量。 var的目的是专门创建局部变量,所以不要使用它,你就在那里。

var fn = function() {
    foo = "Setting foo from in a function";
}

如果要显式影响全局范围,请修改window对象,该对象是全局对象的容器:

var fn = function() {
    window.foo = "Setting foo from in a function";
}

答案 2 :(得分:1)

不使用var,而是在this对象内设置变量。这样,如果您使用window调用该函数,您将设置“全局”变量:

window.foo = "I am top level foo.";

var fn = function(){
    this.foo = "Setting foo from in a function";
}

fn.call(window);
alert(foo);

您也可以使用不同的上下文调用该函数:

var anObject = { foo: "Initial Value" };
fn.call(anObject);
alert(anObject.foo); // Will be the modified value

答案 3 :(得分:0)

您可以在不更改fn的情况下获得此效果,但此代码不适合胆小的人:

<script type="text/javascript">
var gFoo = "";

var fn = function() {
    var foo = "Setting foo from in a function";
}

var fnText = fn.toString();
var newFunction = fnText.substring(0, fnText.length - 1) + "gFoo = foo; }";

eval("var x = " + newFunction + "; x();");
alert(gFoo);
</script>