函數(shù)的五種聲明方式
console.log打印出來(lái)的和返回的沒(méi)關(guān)系尼啡。不用管他為什么返回undefined,因?yàn)樗创a寫(xiě)了
1.具名函數(shù)
沒(méi)有返回值的話一般會(huì)寫(xiě)一個(gè)return undefined就算你不寫(xiě)return undefind 也會(huì)自動(dòng)給你補(bǔ)上育瓜。
2.匿名函數(shù)
匿名函數(shù)需要先給一個(gè)變量,然后賦值給變量要不然會(huì)報(bào)錯(cuò)
3.把有名字的函數(shù)賦值給變量
但是比如var x = function y (){}欣尼,然后你console.log(y)的時(shí)候會(huì)報(bào)錯(cuò)爆雹,因?yàn)檫@個(gè)y只能在x內(nèi)部用,你在外面是會(huì)報(bào)錯(cuò)的愕鼓。y的作用域在里面钙态。然后你console.log(x)的話會(huì)打出y(){}。這個(gè)居然面試經(jīng)彻交危考册倒。
4.
里面都是字符串,用字符串拼接磺送。這個(gè)這么奇怪有人用嗎驻子?
5.最炫的
如果只有一句話可以把return和{}都去掉。如果函數(shù)體里面內(nèi)容太多的話可以用enter或者用分號(hào)隔開(kāi)估灿。
如果參數(shù)只有一個(gè)崇呵,那么()可以去掉。
那以后可以都用這個(gè)方法馅袁。所以其實(shí)就是把function變成了=>域慷,然后如果只有一個(gè)參數(shù)就能少了()只有一句return的話可以省略{}和return。不過(guò)看著高級(jí)很多汗销。
name
變量是直接用的犹褒,用函數(shù)叫做調(diào)用
call
函數(shù)到底是啥,內(nèi)存是怎么存的
stack里面就放了f這個(gè)變量名弛针,f的內(nèi)容是object的地址叠骑,objec里面存放了函數(shù)的代碼,全部以字符串的形式存著削茁。另外這個(gè)object有一個(gè)--proto--:Function 指向函數(shù)的公共屬性宙枷。這個(gè)公共屬性里面有一個(gè)call的API可以調(diào)用函數(shù)掉房。
函數(shù)=函數(shù)名+參數(shù)+函數(shù)體
再回顧一遍
eval:給字符串圃阳,然后把字符串當(dāng)代碼執(zhí)行
自己造一個(gè)函數(shù),先搞個(gè)對(duì)象璧帝,然后加一個(gè)call的屬性,call里面用eavl把函數(shù)執(zhí)行了
所以執(zhí)行函數(shù)的時(shí)候平時(shí)直接f()實(shí)際上是f.call()富寿,所以直接打f沒(méi)用睬隶,出來(lái)的是這個(gè)函數(shù)的代碼。打f()才能執(zhí)行函數(shù)體的結(jié)果页徐。
函數(shù)終極問(wèn)題:可以執(zhí)行代碼的對(duì)象苏潜,叫做函數(shù)
這是js數(shù)據(jù)結(jié)構(gòu)的知識(shí)體系,函數(shù)主要特殊在他的公共屬性变勇,有call恤左,apply,bind還重寫(xiě)了toString本來(lái)object公共屬性有toString的搀绣。一般都用 它的飞袋,函數(shù)用自己的toString。還有其他一些對(duì)象比如Date Error等
世紀(jì)難題:
為什么大家不用f.call(undefined,1,2)而是用f(1,2)链患,第一種才是正確的巧鸭,以后調(diào)用都這么寫(xiě)。因?yàn)榈诙N對(duì)學(xué)this很有幫助麻捻,第一種不行纲仍。
反正聽(tīng)方方的沒(méi)錯(cuò),以后都用f.call(undefined,1,2)就行了
this和arguments
普通模式下贸毕,如果this是undefined瀏覽器會(huì)默認(rèn)把this變成window
如果用'use strict'開(kāi)啟嚴(yán)格模式郑叠,那this就是undefined
如果f.call()傳入其他參數(shù),那么this就會(huì)打出其他參數(shù)明棍。反正結(jié)果就是f.call的第一個(gè)參數(shù)就是this乡革,后面所有參數(shù)加起來(lái)是arguments
那this怎么來(lái)的呢?為啥要有this
就跟new Number沒(méi)人用击蹲,f = new Function()沒(méi)人用一樣署拟,this也是當(dāng)初設(shè)計(jì)的時(shí)候強(qiáng)行要像java所以js之父沒(méi)辦法就放到f.call里面去了。目的是吸引java程序員來(lái)學(xué)js歌豺,然后學(xué)了以后發(fā)現(xiàn)果然是長(zhǎng)得像還可以更方便推穷,然后就上當(dāng)了。所以這些東西都是打廣告用的类咧。
arguments就是除了第一個(gè)參數(shù)后面的參數(shù)馒铃。這些參數(shù)會(huì)組成一個(gè)偽數(shù)組蟹腾。啥是偽數(shù)組?__proto__ 不等于array.prototype的区宇。上面__proto__是指向Object的不是指向array娃殖。所以它看著像數(shù)組但是沒(méi)有數(shù)組的公共屬性,不能用數(shù)組的API议谷,比如push這些都不能用炉爆。
正常的數(shù)組是會(huì)指向Array的。
方方說(shuō)得畫(huà)內(nèi)存圖就是畫(huà)原型鏈
call stack
之所以存在stack是因?yàn)楸緛?lái)內(nèi)存按順序每個(gè)地址上面放了代碼卧晓。然后按地址順序開(kāi)始執(zhí)行代碼芬首,突然到了function a這里發(fā)現(xiàn)這個(gè)a的內(nèi)容是其他函數(shù)的地址,那就得跳到那個(gè)函數(shù)去執(zhí)行啊逼裆。那待會(huì)兒我怎么回來(lái)呢郁稍?那就用一個(gè)叫stack的放a的地址,待會(huì)我回來(lái)就去stack里面拿地址胜宇。
但是如果function a內(nèi)部又有函數(shù)functionb耀怜、b里面又有function c怎么辦呢?同樣再把這個(gè)function b桐愉、function c的地址放到stack里面把财破,待會(huì)c的函數(shù)執(zhí)行完了我再看一下stack就行了。
那現(xiàn)在stack里面放了三個(gè)函數(shù)的地址了仅财。我計(jì)算機(jī)會(huì)先拿哪個(gè)地址呢狈究?如果我拿了a的地址,那我c執(zhí)行完直接回到主函數(shù)去了盏求,因?yàn)閍在主函數(shù)上抖锥。所以a,b都沒(méi)執(zhí)行完啊。因?yàn)槲沂莂執(zhí)行了一半去b的碎罚,b執(zhí)行到一半去c的磅废。本來(lái)c執(zhí)行完我是要拿到c的地址繼續(xù)執(zhí)行b剩下代碼,然后拿到b地址執(zhí)行a剩下代碼荆烈,然后拿到a地址執(zhí)行主函數(shù)代碼拯勉。
所以從結(jié)論上就是新進(jìn)后出,從計(jì)算機(jī)上看它只要去找stack里面放的地址憔购,從上往下一個(gè)個(gè)拿就行了宫峦,不用多想。如果沒(méi)了那就執(zhí)行主函數(shù)玫鸟。
1.function a(){
? ????? function b(){}? ??
? ????? function c(){}
}
2.function a(){
? ? ????function b(){
? ????????? function c(){}
????}
}
注意1导绷,2的stack是不一樣的。
1的順序是:1.a入棧 2.b入棧 3.b出棧 4.c入棧 5.c出棧 6.a出棧
2的順序是:1.a入棧 2.b入棧 3.c入棧 4.c出棧 5.b出棧 6.a出棧
判斷語(yǔ)句也會(huì)入棧
上面同一時(shí)間壓了5次棧屎飘,如果同意棧太多會(huì)不會(huì)不夠呢妥曲?
會(huì)報(bào)錯(cuò)贾费,叫做stack overflow是棧溢出的意思
有句話叫做聲明的時(shí)候不加var就在聲明全局變量,這句話是不完全正確的檐盟。
這種情況下褂萧,在f1里面a = 3,它會(huì)認(rèn)為在給a賦值葵萎,然后在f1里面找a有沒(méi)有聲明导犹。發(fā)現(xiàn)沒(méi)有就去找全局發(fā)現(xiàn)有了,然后就給這個(gè)全局的a賦值羡忘。
這種情況锡足,如果a = 3找了f1發(fā)現(xiàn)沒(méi)有,就在全局有沒(méi)有聲明壳坪。發(fā)現(xiàn)還是沒(méi)有,那除了賦值就順便聲明了一下a然后作為全局變量掰烟。然后再賦值爽蝴。
所以f2的a如果要想是局部變量,必須得加var纫骑,要不然會(huì)往上查蝎亚,查到聲明為止然后再賦值。
找聲明不會(huì)往下找
瀏覽器拿到代碼以后第一步就是變量提升先馆,把全局发框,局部全部找好。文字好懂煤墙,實(shí)際容易錯(cuò)梅惯。
為啥console.log(a)打印出undefined呢?因?yàn)樽兞刻嵘仿野。铣减。。?/p>
變量提升以后就這個(gè)樣子了脚作,所以console.log(a)的時(shí)候a在f1的范圍內(nèi)只做了聲明還沒(méi)有賦值葫哗。只聲明沒(méi)賦值就是undefined
a =2 在 f4.call()前面的話,f4.call()打印出來(lái)a是2球涛,如果a = 2 在 f4.call()后面劣针,那打印出來(lái)就是? a = 1
閉包
想知道細(xì)節(jié)就搜:方應(yīng)杭 閉包