14

当我有一些代码需要多次执行时,我将其包装在一个函数中,这样我就不必重复自己了。有时还需要在页面加载时执行此代码。现在我这样做:

function foo() {
   alert('hello');
}

foo();

我宁愿这样做:

(function foo() {
   alert('hello');
})();

问题是,这只会在页面加载时执行,但如果我尝试在随后的时间调用它foo(),它将无法正常工作。

我猜这是一个范围问题,但有没有办法让自执行函数在稍后被调用时工作?

4

4 回答 4

33

如果你的函数不依赖于返回值,你可以这样做......

var foo = (function bar() {
   alert('hello');
   return bar;
})();   // hello

foo();  // hello

这使用命名函数表达式中的局部引用bar将函数返回给外部foo变量。


或者即使是这样,您也可以使返回值有条件...

var foo = (function bar() {
   alert('hello');
   return foo ? "some other value" : bar;
})();   // hello

alert( foo() );  // hello --- some other value

或者只是手动分配给变量而不是返回......

var foo; 
(function bar() {
   alert('hello');
   foo = bar;
})();   // hello

foo();  // hello

正如@RobG所指出的,某些版本的 IE 会将标识符泄漏到封闭的变量范围中。该标识符将引用您创建的函数的副本。为了使您的 NFE IE 安全(r),您可以取消该引用。

bar = null;

请注意,标识符仍会在作用域链上隐藏具有相同名称的标识符。无效化无济于事,而且局部变量不能被删除,所以明智地选择 NFE 名称。

于 2012-06-05T00:56:02.850 回答
4

要从外部调用,该函数必须从外部可见。理想情况下,您应该让自执行函数将其注入到一些传入的上下文中(在这种情况下,this,它引用全局上下文):

(function(context) {
  var foo = function() {
    alert('hello');
  };
  foo();
  context.foo = foo;
})(this);

...

foo();

更多有趣的模式可以在这里找到。

于 2012-06-05T01:09:08.390 回答
4

如果foo()打算成为一个全局函数,即 的属性window,您可以这样做:

(window.foo = function() {
   alert('hello');
})();

// at some later time
foo();

第一组括号中的表达式执行 create 的赋值foo,但也计算为函数,因此您可以()在最后立即调用它。

即使函数应该返回一个值,这种模式也有效。

于 2012-06-05T01:29:15.890 回答
1

第二个函数foo是函数定义表达式。

在函数定义表达式中,您只能根据“Javascript 权威指南”在函数本身内调用具有名称的函数:

对于函数定义表达式,名称是可选的:如果存在,则名称仅在函数本身的主体内引用函数对象。

它可以在递归函数定义表达式中使用。

例如:

var f = function factorial(n) {
    if (n == 0 || n == 1)
        return 1;
    else
        return n * factorial(n-1);
}
于 2017-06-29T09:07:37.117 回答