2012-06-05 50 views
11

當我有一些代碼時,我需要多次執行,所以我不必重複自己。有時候,還需要在頁面加載時最初執行此代碼。現在我做這種方式:如何在JavaScript中調用自執行函數?

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

foo(); 

我寧願做這種方式:

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

問題是,這將只執行在頁面加載,但如果我嘗試使用叫它後續時間foo()它不會工作。

我猜這是一個範圍問題,但有沒有什麼辦法讓自執行函數工作後得到調用?

+1

我不知道這是否是做的最好的方式。我想這會在一段時間後變得非常混亂。 – Hassan

+3

http://stackoverflow.com/questions/6211466/call-immediately-executing-function-from-outside的可能重複。 – apsillers

+0

也可能重複http://stackoverflow.com/questions/6404196/can-i-name-a-javascript-function-and-execute-it-immediately(它有更好的答案,恕我直言,但問題的措辭不是完全匹配。) – apsillers

回答

29

如果功能不依賴於一個返回值,你可以這樣做......

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名稱。

+0

命名函數表達式**應該是非常有用的,但它們[在IE中破壞](http://kangax.github.com/nfe/#jscript-bugs),因此被大多數人推薦。例如在上面的'typeof bar'中顯示「功能」,即使放置在* IIFE之前。 – RobG

+0

@RobG:沒錯,但這往往是一個無害的問題。如果您在封閉範圍中使用該標識符來引用範圍鏈上的變量,「bar」漏出甚至創建重複函數的事實可能只會很重要。 – 2012-06-05 03:11:08

+0

這裏不是問題,但通常函數表達式的意圖是保持函數「私有」。讓它成爲全球職能可能會產生意想不到的後果,特別是在大型項目中。 – RobG

4

要從外部調用,該功能必須從外部可見。理想情況下,你將有自我執行的函數把它注射在一些情況下通過(在這種情況下,this,它引用了全球範圍內):

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

... 

foo(); 

更有趣的圖案可以發現here

+0

尼斯鏈接,謝謝 – TK123

+1

通過'這是因爲它保證引用全局代碼中的全局對象,'window'不保證引用任何東西,甚至不被定義。 – RobG

+0

@RobG:是的,它會:-)我剛剛提供了一個例子,我明確提到_some在context_中傳遞。由OP決定哪種上下文最適合他。 –

2

如果foo()旨在成爲一個全球性的功能,即,window的屬性,你可以這樣做:

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

// at some later time 
foo(); 

在第一組括號中的表達不分配創建foo,也評估爲函數,所以你可以立即調用()

即使該函數應該返回一個值,該模式也可以工作。

+0

+1沒有理由,這也不能與當地人一起完成。 'var foo; (foo = func ...})()' – 2012-06-05 13:19:11

+0

Thanks @amnotiam。當然你對當地人是對的。出於某種原因,當我寫這個答案時,我試圖把它作爲一個單一的陳述,並避免var聲明 - 我甚至不記得現在爲什麼。 – nnnnnn

0

第二個函數foo是一個函數定義表達式。

對於函數定義表達式,該名稱是可選的:

在函數定義表達式,你只能用函數內部名稱根據「JavaScript中的權威指南」調用的函數(如果存在) ,該名稱僅指函數本身內的功能對象

它可以在遞歸函數定義表達式中使用。

例如:

var f = function factorial(n) { 
    if (n == 0 || n == 1) 
     return 1; 
    else 
     return n * factorial(n-1); 
} 
相關問題