前兩天班級聚會,除了吃喝玩樂就是睡覺扯淡,甚是喜悅,真是獨樂樂不如眾樂樂啊。
PS:畢業的或即將畢業的有時間能聚就聚吧,畢了業以後屬於自己的時間能聚到一塊兒可就少太多了。
現在有點時間來看點東西總結些東西了,又因為前段時間片片斷斷地看了看JavaScript的函數部分,所以抽時間總結下函數的相關部分,當然,裡面有些部分都是自己的理解,如果有理解的不對的地方還請小伙伴們不吝指出。
這一節我結合自己的理解和小伙伴們聊一下函數聲明的聲明提前。
注:有的地方也叫函數聲明提升。翻譯的不一樣,意思一樣,大家理解就行。理解萬歲!
在聊函數聲明的聲明提前之前,有必要介紹下函數定義的幾種方法,大部分小伙伴們應該都不陌生。了解的或者不想了解的就痛快地一滾輪滾下去吧,不熟悉的或者想再熟悉一下的就放慢腳步起步走。
定義函數的方法
定義函數的方法主要有三種:
1.函數聲明(Function Declaration)
2.函數表達式Function Expression)
3.new Function構造函數
其中,經常使用的是函數聲明和函數表達式的函數定義方法,這兩種方法有著很微妙的區別和聯系,而且這兩種方法的使用也容易混淆,所以這篇文章主要總結下這兩種函數定義方法的相關知識點,當然本文的主題依然是關於函數提前的。
函數聲明的典型格式:
function functionName(arg1, arg2, ...){ <!-- function body --> }
函數表達式
•函數表達式的典型格式:
var variable=function(arg1, arg2, ...){ <!-- function body --> }
包含名稱(括弧,函數名)的函數表達式:
var variable=function functionName(arg1, arg2, ...){ <!-- function body --> }
像上面的帶有名稱的函數表達式可以用來遞歸:
var variable=function functionName(x){ if(x<=1) return 1; else return x*functionName(x); }
聲明提前
var聲明提前
小伙伴們應該都聽說過聲明提前的說法,我想在此再次重申一遍,因為聲明提前是函數聲明和函數表達式的一個重要區別,對於我們進一步理解這兩種函數定義方法有著重要的意義。
但是再說函數聲明提前之前呢,有必要說一下var聲明提前。
先給出var聲明提前的結論:
變量在聲明它們的腳本或函數中都是有定義的,變量聲明語句會被提前到腳本或函數的頂部。但是,變量初始化的操作還是在原來var語句的位置執行,在聲明語句之前變量的值是undefined。
上面的結論中可以總結出三個簡單的點:
1.變量聲明會提前到函數的頂部;
2.只是聲明被提前,初始化不提前,初始化還在原來初始化的位置進行初始化;
3.在聲明之前變量的值是undefined。
還是來例子實在:
var handsome='handsome'; function handsomeToUgly(){ alert(handsome); var handsome='ugly'; alert(handsome); } handsomeToUgly();
正確的輸出結果是:
先輸出undefined,然後輸出ugly。
錯誤的輸出結果是:
先輸出handsome,然後輸出ugly。
這裡正是變量聲明提前起到的作用。該handsome局部變量在整個函數體內都是有定義的,在函數體內的handsome變量壓住了,哦不對,是覆蓋住了同名的handsome全局變量,因為變量聲明提前,即var handsome被提前至函數的頂部,就是這個樣子:
var handsome='handsome'; function handsomeToUgly(){ var handsome; alert(handsome); var handsome='ugly'; alert(handsome); } handsomeToUgly();
所以說在alert(handsome)之前,已經有了var handsome聲明,由上面提到的
在聲明之前變量的值是undefined
所以第一個輸出undefined。
又因為上面提到的:
只是聲明被提前,初始化不提前,初始化還在原來初始化的位置進行初始化
所以第二個輸出ugly。
函數聲明提前
接下倆我們結合var聲明提前開始聊函數聲明的聲明提前。
函數聲明的聲明提前小伙伴們應該很熟悉,舉個再熟悉不過的例子。
sayTruth();<!-- 函數聲明 --> function sayTruth(){ alert('myvin is handsome.'); } sayTruth();<!-- 函數表達式 --> var sayTruth=function(){ alert('myvin is handsome.'); }
小伙伴們都知道,對於函數聲明的函數定義方法,即上面的第一種函數調用方法是正確的,可以輸出myvin is handsome.的真理,因為函數調用語句可以放在函數聲明之後。而對於函數表達式的函數定義方法,即上面的第二種函數調用的方法是不能輸出myvin is handsome.的正確結果的。
結合上面的myvin is handsome.例子,函數聲明提前的結論似乎很好理解,不就是在使用函數聲明的函數定義方法的時候,函數調用可以放在任意位置嘛。對啊,你說的很對啊,小伙伴,我都不知道怎麼反駁你了。那就容我再扯幾句。
從小伙伴所說的
不就是在使用函數聲明的函數定義方法的時候,函數調用可以放在任意位置嘛
可以引出一點:
函數聲明提前的時候,函數聲明和函數體均提前了。
而且:
函數聲明是在預執行期執行的,就是說函數聲明是在浏覽器准備執行代碼的時候執行的。因為函數聲明在預執行期被執行,所以到了執行期,函數聲明就不再執行(人家都執行過了自然就不再執行了)。
上面是一點。
函數表達式為什麼不能聲明提前
我們再說一點:為什麼函數表達式不能像函數聲明那樣進行函數聲明提前呢?
辛虧我知道一點兒,否則真不知道我該怎麼回答呢?
咳咳,按照我的理解給小伙伴們解釋一下下:
我們上面說了var的聲明提前,注意我上面提過的:
只是聲明被提前,初始化不提前,初始化還在原來初始化的位置進行初始化
Ok,我們把函數表達式擺在這看看:
var variable=function(arg1, arg2, ...){ <!-- function body --> }
函數表達式就是把函數定義的方式寫成表達式的方式(貌似是白說,但是這對於解釋和理解為毛函數表達式不能函數聲明提前具有良好的療效),就是把一個函數對象賦值給一個變量,所以我們把函數表達式寫成這個樣子:
var varible=5看到這,也許小伙伴們會明白了,一個是把一個值賦值給一個變量,一個是把函數對象賦值給一個變量,所以對於函數表達式,變量賦值是不會提前的,即function(arg1, arg2, ...){<!-- function body -->}是不會提前的,所以函數定義並沒有被執行,所以函數表達式不能像函數聲明那樣進行函數聲明提前。
函數聲明提前的實例分析
還是那句話,還是例子來的實在:
sayTruth(); if(1){ function sayTruth(){alert('myvin is handsome')}; } else{ function sayTruth(){alert('myvin is ugly')}; }
在浏覽器不拋出錯誤的情況下(請自行測試相應的浏覽器是否有拋出錯誤的情況,為啥我不測試?我能說我懶麼。。。),浏覽器的輸出結果是輸出myvin is ugly(我不願承認,但是事實就是這樣啊啊啊啊,難道道出了人丑就該多讀書??????)。
為什麼呢?當然是聲明提前了。因為函數聲明提前,所以函數聲明會在代碼執行前進行解析,執行順序是這樣的,先解析function sayTruth(){alert('myvin is handsome')},在解析function sayTruth(){alert('myvin is ugly')},覆蓋了前面的函數聲明,當我們調用sayTruth()函數的時候,也就是到了代碼執行期間,聲明會被忽略,所以自然會輸出myvin is ugly(好殘酷的現實。。。)。忘了的可以看上面說過的:
函數聲明是在預執行期執行的,就是說函數聲明是在浏覽器准備執行代碼的時候執行的。因為函數聲明在預執行期被執行,所以到了執行期,函數聲明就不再執行了(人家都執行過了自然就不再執行了)。
小了個結
關於函數聲明的函數提前(提升)就聊到這裡先,希望我的理解和扯淡能夠對有需要的小伙伴有所幫助。
當然,實踐出真知。對事物的了解、認知和運用還是在於多看多用多總結,記得有句名言,是講聲明和實踐的:“動起來,為新的聲明喝彩。”。
以上這篇淺析函數聲明和函數表達式——函數聲明的聲明提前就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持。