2009-06-18 110 views
410

以下幾行代碼有什麼區別?JavaScript中的函數表達式與聲明有什麼區別?

//Function declaration 
function foo() { return 5; } 

//Anonymous function expression 
var foo = function() { return 5; } 

//Named function expression 
var foo = function foo() { return 5; } 
  • 什麼是名爲/匿名函數表達式?
  • 什麼是聲明的函數?
  • 瀏覽器如何處理這些結構的不同?

對類似問題(var functionName = function() {} vs function functionName() {})的回答不完全正確嗎?

+0

var foo = function foo() { return 5; } 

繼承人它展示瞭如何使用遞歸調用的可能性的例子這是[關於命名函數表達式的好文章](http://kangax.github.com/nfe)。函數表達式與聲明在第一節中討論。 – 2009-06-18 17:09:25

+0

海事組織的主要區別在於提升。這裏是關於這個主題的一篇很好的文章:http://www.adequatelygood.com/JavaScript-Scoping-and-Histing.html – 2014-11-18 18:03:59

回答

10

第一個聲明取決於聲明它的上下文。

如果在全局上下文中聲明,它將創建一個名爲「foo」的隱含全局變量,它將是一個指向該函數的變量。因此函數調用「foo()」可以在JavaScript程序中的任何地方進行。

如果在一個封閉創建功能,將創建一個名爲「富」然後你就可以用它來調用閉包功能與「富()」隱含的局部變量

編輯:

我也應該說,函數語句(第一個)在函數表達式(其他2)之前被解析。這意味着如果您在腳本的底部聲明函數,您仍然可以在頂部使用它。函數表達式僅在被執行代碼命中時才被評估。

END EDIT

語句2 & 3相當於彼此幾乎。再次,如果在全局上下文中使用,它們將創建全局變量,並且如果在閉包中使用,則會創建局部變量。但值得注意的是,語句3將忽略函數名稱,所以本質上你可以調用函數。因此

var foo = function foo() { return 5; } 

相同

var foo = function fooYou() { return 5; } 
+19

`fooYou`不被忽略。它在函數體中可見,所以函數可以引用它自己(例如實現遞歸)。 – 2010-07-27 14:06:36

+1

這是一個很好的觀點。我沒有想到:) – Alex 2011-04-30 08:59:22

+7

另外,命名函數表達式對調試很有用:`var foo = function fooYou(){return 5; };的console.log(FOO); console.log(foo.name);`將打印fooYou()/ fooYou`(Firefox),`[Function:fooYou]/fooYou`(node.js),`function fooYou(){return 5; }/fooYou`(Chrome)或這些行的獨立內容,具體取決於您執行的位置。 – Gilead 2013-01-15 15:41:57

335

他們實際上真的很相似。你怎麼稱呼它們是完全一樣的。區別在於瀏覽器如何將它們加載到執行上下文中。

函數聲明在任何代碼執行之前加載。

函數表達式僅在解釋器到達該行代碼時加載。

所以如果你試圖在加載之前調用函數表達式,你會得到一個錯誤!如果你調用函數聲明,它會一直工作,因爲在加載所有聲明之前不能調用代碼。

舉例:函數表達式

alert(foo()); // ERROR! foo wasn't loaded yet 
var foo = function() { return 5; } 

舉例:函數聲明

alert(foo()); // Alerts 5. Declarations are loaded before any code can run. 
function foo() { return 5; } 


關於你問題的第二部分:

var foo = function foo() { return 5; }是真正的SAM另外兩個。這只是這行代碼用於導致safari中的錯誤,儘管它不再。

1

雖然完整的區別比較複雜,但唯一與我有關的區別是機器創建函數對象時。在聲明的情況下,在執行任何語句之前,但是在調用聲明體(是全局代碼體或子函數的聲明)之前,對於表達式而言,它是在執行聲明時執行。除此之外,所有的意圖和目的都是瀏覽器對待它們。

爲了幫助你理解,看看這個性能test,它破壞了我內部聲明的函數的假設,當外部函數被調用時不需要由機器重新創建。有點恥辱,因爲我喜歡這樣寫代碼。

79

函數聲明

function foo() { ... } 

因爲功能提升的,函數聲明這樣既可以和之後的定義之前被調用。

函數表達式

  1. 命名的函數表達式

    var foo = function bar() { ... } 
    
  2. 匿名函數表達式

    var foo = function() { ... } 
    

foo()只能在創建後調用。

Immediately-Invoked Function Expression (IIFE)
(function() { ... }()); 

結論

克羅克福德推薦使用函數表達式,因爲它清楚地表明,foo是包含函數值的變量。那麼,我個人更喜歡使用宣言,除非有表達的理由。

17

關於第三個定義:

a = function b(i) { 
    if (i>10) { 
    return i; 
    } 
    else { 
    return b(++i); 
    } 
} 

console.log(a(5)); // outputs 11 
console.log(a(10)); // outputs 11 
console.log(a(11)); // outputs 11 
console.log(a(15)); // outputs 15 

編輯: 更有意思的例子與封閉:

a = function(c) { 
return function b(i){ 
    if (i>c) { 
    return i; 
    } 
    return b(++i); 
} 
} 
d = a(5); 
console.log(d(3)); // outputs 6 
console.log(d(8)); // outputs 8 
相關問題