javascript中宣告函數的方法有兩種:函數宣告式和函數表達式.
區別如下:
1).以函數宣告的方法定義的函數,函數名是必須的,而函數表達式的函數名是可選的.
2).以函數宣告的方法定義的函數,函數可以在函數宣告之前呼叫,而函數表達式的函數只能在宣告之後呼叫.
3).以函數聲明的方法定義的函數並不是真正的聲明,它們僅僅可以出現在全局中,或者嵌套在其他的函數中,但是它們不能出現在循環,條件或者try/catch/ finally中,而
函數表達式可以在任何地方宣告.
以下分別用兩種方法定義函數:
//函数声明式 function greeting(){ console.log("hello world"); } //函数表达式 var greeting = function(){ console.log("hello world"); }
下面一個有趣的javascript:
function f() { console.log('I am outside!'); } (function () { if(false) { // 重复声明一次函数f function f() { console.log('I am inside!'); } } f(); }());
會輸出什麼呢?第一個反應應該是"I am outside"吧. 結果在chrome中輸出"I am inside",IE11直接報錯,firefox低一點的版本輸出"I am outside"...
chrome輸出的結果很明確的反應了用函數宣告式宣告的函數的特性--函數在宣告之前就可以呼叫.
IE報錯顯示缺少物件,因為函數宣告在了條件裡,違反了函數宣告式的原則.
函數表達式的作用域:
如果函數表達式宣告的函數有函數名稱,那麼這個函數名稱就相當於這個函數的一個局部變數,只能在函數內部呼叫,舉個栗子:
var f = function fact(x) { if (x <= 1) return 1; else return x*fact(x-1); }; alert(fact()); // Uncaught ReferenceError: fact is not defined
fact()在函數內部可以呼叫,在函數外部呼叫就會報錯:fact未定義.
fact
我們再來詳細看下
函數宣告
函數宣告範例程式碼
程式碼如下:
function fn () { console.log('fn 函数执行..'); // code.. }
這樣我們就聲明了一個名稱為fn的函數,這裡出個思考,你認為在這個函數的上面來呼叫他的話會執行嗎?還是會報錯?
程式碼如下:fn(); // 在先前呼叫我們宣告的fn函數 function fn () { console.log('fn 函數執行..'); // code..}
控制台輸出結果:
是的,此時fn函數是可以被呼叫的,這裡來總結下原因。
總結:
1:此時fn函數是變數的結果,預設儲存在全域上下文的變數中(可用 window.函數名稱 來驗證)
2:此方式為函數聲明,在進入全域上下文階段創建,程式碼執行階段,它們已經可用。 ps:javaScript每次進入方法時都會先初始化上下文環境(由全域 → 局部)
3:它可以影響變數物件(僅影響儲存在上下文中的變數)
函數表達式
函數表達式範例程式碼
程式碼如下:
var fn = function () { console.log('fn 函数【表达式】声明执行..') // code.. }
這樣我們就聲明了一個匿名函數,並且把它的引用指向了變數fn?
再次在該表達式宣告的函數上下方各呼叫一次,來看控制台的輸出結果。
程式碼如下:
// 为了清晰的看到控制台的输出,我们在各自调用前后做个标记,增加可读性。 console.log('之前调用开始..'); fn(); console.log('之前调用结束..'); var fn = function () { console.log('fn 函数【表达式】声明执行..') // code.. } console.log('之后调用开始..'); fn(); console.log('之后调用开始..');
控制台列印結果:
可以看到程式碼執行到第一次呼叫fn()函數的時候,提示:fn is not a function (fn 不是一個方法),遇到錯誤而終止運行。
這說明在第一次呼叫fn()的同時,var fn 變數並沒有做為全域物件的一個屬性而存在,且 fn 所引用的匿名函數上下文也沒有被初始化,所以在他之前呼叫失敗。
程式碼如下:
// 现在先把之前的调用逻辑给注释掉,再看下控制台的输出 // console.log('之前调用开始..'); // fn(); // console.log('之前调用结束..'); var fn = function () { console.log('fn 函数【表达式】声明执行..') // code.. } console.log('之后调用开始..'); fn(); // 在表达式之后调用 console.log('之后调用开始..');
控制台列印結果:
可以看出,在該表達式函數之後來呼叫是可以的,來總結下那是為什麼呢?
總結:
1:首先變數本身不做為一個函數存在,而是一個匿名函數的參考(值類型的不屬於引用)
2:在程式碼執行階段,初始化全域上下文時,它沒有被做為全域的一個屬性而存在,所以不會造成變數物件的污染
3:此類型的聲明一般在插件的開發較常見,也可做為閉包中回呼函數的呼叫
所以 function fn () {} 不等於 var fn = function () {} ,他們有本質上的差別。
以上就是本文的全部內容了,思路很清晰,對比也很明確,是篇非常不錯的文章,小夥伴們一定要仔細研讀下