javascript中的函數式聲明與變數式聲明
觀察下面兩段代碼,試寫出hello('word');的運行結果: // 變數式聲明function hello(msg){ alert(msg); var msg = function(){}; alert(msg);} //函數式聲明function hello(msg){ alert(msg); function msg (){}; alert(msg);} 對於變數式聲明,首先彈出word,然後彈出function,而函數式聲明,則兩次都是彈出function.這是為什麼呢? 一: 函數式聲明 function hello(msg){ alert(msg); //放在最前面的位置列印msg,是function function msg(){ //這個msg是函數式聲明,它會貫穿於整個fun函數的範圍 //也就是說,只要fun一旦調用,甚至只要是進入文法分析階段 //那麼msg函數就會首先解析,你可以把它想象成它是在fun函數 //內的第一個變數。有的書上稱這種現象為聲明被提前或提升。 } alert(msg);//放在最末尾的位置列印msg,也是function // 說明函數式聲明在hello範圍內部是貫穿的} 二:變數式聲明 function hello(msg){ alert(abc); // 此時為undefined var abc = function(){ //這種是變數式聲明,它在fun函數內的位置是固定的,也就是說 // var abc之前,abc的值在fun內是undefined // var abc之後,abc才是它聲明的值 // 這種方式你可以理解成在fun函數的第一行寫了一個var abc; // 也正因為如此,fun內聲明的變數,會切斷外部變數的引用; // 不論在hello範圍之外,abc的值是多少,在hello內部,在var abc之前,始終是undefined // 這是面試官最喜歡光顧的地方之一 } alert(abc); // 此時才是function // 這裡把abc換成msg,道理也是一樣的。對於hello內部來說,它的形參,就相當於是hello內部的局部變數。 // 這裡有意用abc來替換msg,其實是為了簡化問題,減少幹擾項。既然是都hello內的局域變數,那麼在聲明之前 // 它的值為undefined也就是理所當然的事了。這裡唯一有個要注意的地方就是,形參的聲明,出現在所有局部變數之前。 // 後面對局部變數進行重複聲明,系統會直接無視重複的聲明過程,但是聲明同時有賦值的話除外。 } 總結一點:函數式聲明會上升到所屬範圍的最前面, 變數式聲明則不會. 最後補充一點:var abc = function(){}; 實際上是abc儲存了一個無名函數的引用;本質上abc還是一個變數. 而 function abc(){} 是一個有名函數;本質上abc是函數; 如果你喜歡,你可以用多個變數儲存同一個函數的引用: var xxx = abc; var bbb = abc;引用可以無數,但是真身始終唯一。 // xxx = null,bbb=null之後,abc該幹嘛幹嘛,而 var abc = function(){}; abc = null之後你就徹底的失去了有關abc的一切。 abc從此石沉大海,從江湖上隱姓埋名,銷聲匿跡....... 雖然兩者在功能上是等價的,但是呢,我個人還是蠻傾向於把子函數, 人為的寫在前面,這是為了避免壓縮合并時,造成各種意外的結果。 如果不是通用方法,我習慣用變數式聲明,當然,這隻是個人習慣。 對於函數式聲明,它在整個範圍內可見,有的書上說是聲明提升,有的說是聲明提前。其實叫什麼不重要,理解這種現象發生了什麼,會產生什麼影響才是根本。最後還要強調一點:命名函數運算式的名字只在該函數的範圍內部有效。也就是說,在hello函數內,無論用哪種方式聲明msg這個函數,那麼出了hello函數,都是不存在的。