5.function類型
函數(shù)實(shí)際上是一個(gè)對(duì)象弓千。因此函數(shù)名的本質(zhì)是一個(gè)指向函數(shù)對(duì)象的指針兵扬。
他并不與某個(gè)函數(shù)綁定,這同時(shí)也就解釋了將某一個(gè)函數(shù)名多次定義乞巧,js只會(huì)調(diào)用最后一次定義的內(nèi)容涨椒。
另外,由于我們說函數(shù)名實(shí)際上是一個(gè)指向函數(shù)對(duì)象的指針绽媒,那么這也就意味著同一個(gè)函數(shù)可以有多個(gè)名字蚕冬。我們可以在定義一個(gè)函數(shù)后,定義另外一個(gè)變量 = 之前的指針是辕,這樣同一個(gè)函數(shù)就有兩個(gè)名字了囤热。因此,函數(shù)名只是指向函數(shù)對(duì)象的引用获三,這個(gè)定義非常重要旁蔼。要訪問函數(shù)指針,只需要訪問變量值石窑,而去掉括號(hào)即可牌芋。
5.1沒有重載(深入講解)
函數(shù)名是一個(gè)指針,他實(shí)際上并不與某個(gè)函數(shù)綁定松逊,這同時(shí)也就解釋了將某一個(gè)函數(shù)名多次定義躺屁,js只會(huì)調(diào)用最后一次定義的內(nèi)容。也就是沒有重載的原因经宏。
5.2函數(shù)聲明和函數(shù)表達(dá)式
在運(yùn)行js代碼時(shí)犀暑,解析器和率先讀取到函數(shù)的聲明,并且使其在任何代碼被執(zhí)行前設(shè)置為可訪問狀態(tài)烁兰。而真正的函數(shù)表達(dá)式耐亏,則必須等到解析器執(zhí)行到了調(diào)用它的具體代碼時(shí),才會(huì)被解釋和執(zhí)行沪斟。
為了驗(yàn)證這個(gè)結(jié)論,我們可以使用兩種函數(shù)定義的方式,檢查函數(shù)聲明的升格情況:
這是因?yàn)橘x值的函數(shù)定義并不是函數(shù)聲明择吊,不會(huì)在代碼被解釋前執(zhí)行函數(shù)的升格操作李根。因此在運(yùn)行到console.log(sum2(a,b))時(shí),sum2并沒有被定義几睛,它也根本沒有指向文中定義的函數(shù)對(duì)象房轿,所以報(bào)錯(cuò)sum2 is not a function也不足為奇了。
5.3作為值的函數(shù)
因?yàn)槲覀兛梢詫⒑瘮?shù)名看做是指向函數(shù)對(duì)象的引用類型變量所森,因此囱持,可以將函數(shù)作為一個(gè)參數(shù)傳遞給另外一個(gè)函數(shù),就是理所當(dāng)然的了焕济。
除此之外,在一個(gè)函數(shù)中返回另外一個(gè)函數(shù)也是非常好的寫法:舉個(gè)例子肝匆,在一個(gè)函數(shù)的連環(huán)定義中粒蜈,內(nèi)容其實(shí)有三個(gè)參數(shù):propertyName,object1旗国,object2:
我們可以在外面的函數(shù)中傳入一個(gè)propertyName的值枯怖,隨后這個(gè)函數(shù)會(huì)返回一個(gè)函數(shù)的定義:
function(object1,object2){? do some things}
此時(shí)這個(gè)被返回的函數(shù)就可以在別的函數(shù)中作為一個(gè)參數(shù)被使用過了:最簡(jiǎn)單的使用例子就是我們定義比較函數(shù):
5.4函數(shù)內(nèi)部的屬性
函數(shù)內(nèi)部有兩個(gè)特殊屬性:arguments和this。
① arguments我們?cè)谇拔亩啻翁岬竭^能曾,他是一個(gè)類數(shù)組的保存參數(shù)的對(duì)象度硝,雖然arguments的主要用途是保存參數(shù)對(duì)象,但這個(gè)對(duì)象其實(shí)還有一個(gè)叫做callee的屬性寿冕,這個(gè)屬性是一個(gè)引用類型的指針蕊程,它指向擁有arguments對(duì)象的函數(shù)。
而我們可以使用它驼唱,在函數(shù)發(fā)生遞歸時(shí)藻茂,一旦想要改變函數(shù)名,那么遞歸就會(huì)失效玫恳,但是使用callee替代原來的函數(shù)名指向函數(shù)就不會(huì)有什么問題:
② 函數(shù)內(nèi)部地另外一個(gè)特殊對(duì)象是this辨赐。this是在js編程中經(jīng)常搞不清楚的一點(diǎn)。但是書里有一句清晰的定義京办,即永遠(yuǎn)記住一句話:this指向的是函數(shù)據(jù)以引用的環(huán)境對(duì)象拧额∶呛危或者說坡疼,this的值就是據(jù)以執(zhí)行的環(huán)境對(duì)象。
換句話說叶雹,函數(shù)定義在哪個(gè)類里,它所指向的就是哪個(gè)類县袱。
對(duì)于第一個(gè)this.color佑力,因?yàn)槠涠x在全局類里式散,環(huán)境對(duì)象為window,因此color為全局的red打颤。
對(duì)于第二個(gè)this.color暴拄,因?yàn)槠涫菑膐b1.f()發(fā)起的,環(huán)境對(duì)象為ob1,因此this指向ob1编饺,因此color為類內(nèi)的blue乖篷。
對(duì)于第三個(gè)this.color,雖然是在函數(shù)內(nèi)定義透且,但是因?yàn)闀?huì)發(fā)生函數(shù)定義升格撕蔼,因此其環(huán)境是全局類,環(huán)境對(duì)象為winodw秽誊,因此color為全局的red鲸沮。
但是在這里同時(shí)要注意,函數(shù)的名字僅僅是一個(gè)包含指針的變量锅论。因此讼溺,即便在不同的環(huán)境里,打印color得到不同的值最易,但其實(shí)全局的fun1與ob1.f兩個(gè)指針同樣指向一個(gè)函數(shù)怒坯。二者做邏輯判斷也會(huì)返回true。
③ 還有一個(gè)函數(shù)屬性叫做caller,它返回調(diào)用當(dāng)前函數(shù)的函數(shù)的引用藻懒。定義讀起來很繞剔猿,但是看個(gè)例子就明白了:
5.5函數(shù)的屬性與方法
前文我們提到過,函數(shù)其實(shí)也是對(duì)象嬉荆,因此函數(shù)也有屬性和方法归敬。每個(gè)函數(shù)都有兩個(gè)屬性:length和protype,以及三個(gè)方法:apply和call员寇,和bind弄慰。
length為這個(gè)函數(shù)在定義時(shí)寫入的參數(shù)個(gè)數(shù)。
prototype為真正保存引用類型所有實(shí)例方法的地方蝶锋,它是函數(shù)的一個(gè)子對(duì)象陆爽,在第六章會(huì)詳細(xì)介紹這個(gè)屬性,在這先按下不表扳缕。另外慌闭,prototype屬性是不可以枚舉的别威,因此for-in無法發(fā)現(xiàn)該屬性。
apply和call的用途都是在特定的作用域中調(diào)用函數(shù)驴剔。實(shí)際功能就是設(shè)置函數(shù)體內(nèi)this的值省古。
apply接受兩個(gè)參數(shù):1是特定的作用域,另外一個(gè)是參數(shù)數(shù)組丧失。而call與apply唯一的不同僅僅是call是填參數(shù)數(shù)組豺妓,而apply是把參數(shù)全部一個(gè)一個(gè)列進(jìn)去。
首先運(yùn)行fun2時(shí)布讹,this指向window琳拭,因此this.c = 10,fun1的結(jié)果也就是13。
當(dāng)將d.f也指向函數(shù)fun2時(shí)描验,this指向了d白嘁,因此this.c = 20,fun1的結(jié)果也就變成了23膘流。
apply和call可以有效的指定函數(shù)在何種作用域運(yùn)行絮缅,我們可以首先定義類,再將不同的類作為環(huán)境傳入函數(shù)中去呼股,這時(shí)函數(shù)中的this.prototype的值就會(huì)變成不同環(huán)境域下的值耕魄。
而bind與前二者不同,bind是根據(jù)已有的函數(shù)復(fù)制一個(gè)新的函數(shù)卖怜,而這個(gè)新的函數(shù)的作用域和this指向的對(duì)象由開發(fā)人員自己決定屎开。一般使用可以分為三個(gè)步驟:
另外其實(shí)每個(gè)函數(shù)也都有toLocaleString,toString,valueOf三個(gè)方法甩鳄,但是因?yàn)椴煌臑g覽器返回的值不同逞度,但基本上都是函數(shù)實(shí)現(xiàn)的內(nèi)容,這些信息在調(diào)試代碼時(shí)是比較有用的妙啃。在這就不多贅述了档泽。