大家好,我是IT修真院武漢分院第7期的學員景鑫,一枚正直純潔善良的WEB前端程序員。
1.背景介紹
在詳細講解自執(zhí)行函數(shù)之前,我們先來說一下這個函數(shù)在叫法上的爭議。實際上不同的人對自執(zhí)行函數(shù)的理解不太一樣,第一種理解是,自執(zhí)行即自動執(zhí)行,也就是大家平時所謂的立即執(zhí)行函數(shù)。
還有一種理解,即自執(zhí)行函數(shù)是在函數(shù)內(nèi)部執(zhí)行函數(shù)本身,即我們平時常說的遞歸函數(shù)。不管是哪種理解,我們都沒必要去糾結(jié)叫法上的準確與否,因為相比于自執(zhí)行函數(shù),立即執(zhí)行函數(shù)和遞歸函數(shù)這兩種叫法是我們更加熟悉的,實際上平時也很少會看到自執(zhí)行函數(shù)這種叫法。立即執(zhí)行函數(shù)和遞歸函數(shù)都很重要,因此今天打算對兩種函數(shù)都做一下介紹。
2.知識剖析
知識點1:直接在函數(shù)后面加()就可以立即執(zhí)行嗎?在函數(shù)聲明后面加括號為什么會報錯?
知識點2:如何實現(xiàn)立即執(zhí)行函數(shù)
知識點3:遞歸函數(shù)的幾種用法
3.常見問題
對函數(shù)聲明以及函數(shù)表達式理解不夠深入
不知道立即執(zhí)行函數(shù)的用法
4.解決方案
見demo
5.編碼實戰(zhàn)
5.1對于函數(shù)表達式,在后面加括號即可以讓函數(shù)立即執(zhí)行;例如下面這個函數(shù),至于為什么加了括號就可以立即執(zhí)行,我們可以這么理解,就是像fn1();這樣寫的話,函數(shù) 可以立即執(zhí)行是沒問題的,我們在經(jīng)常會用到,那么對于函數(shù)表達式來說,fn1就是對后面的匿名函數(shù)的一個引用,因此在后面的匿名函數(shù)后直接加括號,自然也就可以立即執(zhí)行

5.2但是對于下面這個函數(shù),如果直接加()就會報錯;如果按照上面的思路去理解,在匿名函數(shù)后面直接加上()應(yīng)該是可以立即執(zhí)行的,但是下面這個函數(shù)之所以會報錯,而且會報兩個錯誤,是因為js引擎在解析js代碼的時候,遇到以function打頭的函數(shù)會當做函數(shù)聲明,然后會檢查語法錯誤,那么第一個括號處的語法錯誤在于函數(shù)聲明是必須要有函數(shù)名字的,而()前面沒有所以報錯;第二個括號處的語法錯誤在于函數(shù)聲明到第二個花括號處,就已經(jīng)算是結(jié)尾了,后面的()會被當作分組操作符,這個()實際上已經(jīng)和函數(shù)聲明沒關(guān)系了,但是既然有了分組操作符,那就要有表達式,不然會報錯;

按照上面的分析,我們?nèi)绻诘谝粋€()前面加上函數(shù)名稱,在第二個()里面加入表達式,那么久不會報錯了,我們來看一下效果

可以看到修改了那兩處的問題以后,報錯消失了,但是這個時候函數(shù)并沒有執(zhí)行,原因上面也已經(jīng)提到了,就是一旦被當作函數(shù)聲明,那么到花括號處就算為止了,后面的()就只當作一個分組操作符,和函數(shù)沒有任何關(guān)系了
5.3那么想讓這種匿名函數(shù)直接執(zhí)行應(yīng)該怎么辦呢,其實很簡單,就是在function前面加上一些操作符,這樣js引擎在解析的時候就不會把它當成是函數(shù)聲明了



5.4以下為最簡單的遞歸函數(shù),即在函數(shù)內(nèi)部調(diào)用函數(shù)本身。

這種函數(shù)有個問題,就是當函數(shù)被其他變量引用,而原函數(shù)名又被設(shè)置為空對象后,遞歸函數(shù)就會報錯

5.5利用argumens.callee來解決這個問題,argumens.callee指向當前的函數(shù);

但是這個方法在嚴格模式下是不可使用的,因此還不夠完美
5.6利用函數(shù)表達式構(gòu)造遞歸函數(shù)

6.拓展思考
立即執(zhí)行函數(shù)有哪些用處?
立即執(zhí)行函數(shù)有很多用處,下面舉一個例子:
在下面這個函數(shù)中,result是一個函數(shù)數(shù)組,希望達到的效果應(yīng)該執(zhí)行數(shù)組中的任何一個函數(shù),得到的值都應(yīng)該和該函數(shù)在數(shù)組中的索引值是一樣的,但是實際情況是所有函數(shù)執(zhí)行后得到的值都是10。之所以會這樣是因為result數(shù)組取值的時候,是通過內(nèi)部函數(shù)去返回外部變量i的值來取得的,由于內(nèi)部函數(shù)會創(chuàng)造一個自己的作用域鏈,作用域鏈中存放的是i這個外部變量對象,這個變量對象對內(nèi)部函數(shù)來說只有一個,for循環(huán)執(zhí)行完成后的最后的值,即10;

這個問題可以通過在給result數(shù)組取值外面加立即執(zhí)行函數(shù)來解決,立即執(zhí)行函數(shù)外面的()里面是可以傳參的,下面這個用法中就是把外部變量i的值通過傳參傳給了num,然后把num的值又傳給了result,這樣最后函數(shù)數(shù)組result中每一個函數(shù)都是返回當時具體的值,即i當時的值,而不是i最后的值。

7.參考文獻
參考一:湯姆大叔的博客之立即調(diào)用的函數(shù)表達式?
8.更多討論
函數(shù)這一部分,從執(zhí)行環(huán)境、作用域鏈、函數(shù)聲明函數(shù)表達式,到閉包、構(gòu)造函數(shù)和原型鏈都是連在一塊的,類似的函數(shù)問題大家都可以一起討論一下
課后問題:
閉包和匿名函數(shù)的區(qū)別?
答:匿名函數(shù)上面已經(jīng)見過了,類似于常用函數(shù)表達式中,function后面直接接一個(),沒有函數(shù)名字,即為匿名函數(shù);閉包是在某個函數(shù)內(nèi)部的函數(shù),由于閉包的作用域鏈包含有外部函數(shù)的變量對象,因此它可以訪問外部函數(shù)變量,這個叫閉包
視頻鏈接:
PPT鏈接:PPT?