07 js02 函數

函數 封裝代碼實現某個功能,最初思路解決代碼重復度高的問題,類似于變量(就是一個筐,往里面填充內容即可) 【編程思想:高內聚、低耦合】【聚焦點:參數和返回值,后續就是函數的嵌套,才延生出作用域、閉包等問題,然后尋求解決方案】

1、函數的基本認知:

(1).函數聲明、調用:function test(){};? test:?函數名/函數引用;?test();?函數執行;[function/var 都是關鍵字; 函數名命名規則:小駝峰規則(并非是語法規則,而是開發規范)]【functiontheFirstName(){} ?document.write(theFirstName);// 打印出函數體,絕對不是地址,區別于編譯性語言,解釋性語言是打印不出地址的】

(2).函數表達式:指代的便是匿名函數表達式;

(3).參數的使用:使函數功能更加豐富;[形參==>?函數內隱式var了多個變量,形參和實參都是變量,它們可以是變量的任何類型:原始值/引用值,取決于函數封裝的代碼要實現的功能]

參數個數問題、實參列表;[實參與形參傳遞時最好要相互對應,要不后續會遇到函數內部封裝好的對象,event/error等的使用,避免出錯]??

映射規則、特殊性;[arguments:每個函數內部系統都會隱式定義一個實參列表,實參都有地方存放,console.log(arguments)]

例子:

(4).return(函數結束條件及返回值,如果不寫 -> 函數末尾隱式添加 return undefined;)

(5).作用域:全局變量/局部變量的訪問規則:

嵌套函數:里面可訪問外面,外面不可訪問里面;兩個相互獨立的函數也不可互相訪問;

補充:定義函數的方式:

[1].函數聲明;[2].函數表達式(匿名函數表達式);[3].使用對象Function,類似Number/Boolean/String/Array/Object;(了解即可)

[4].函數在對象中的使用,稱為方法;[5].匿名函數function(){},箭頭函數() => { };?這兩種一般作為回調函數使用(作為其他函數的參數),或者當作立即執行函數使用;

箭頭函數:() => {};? =>?表示函數中的大括號,{ }?函數體;( )函數參數,當函數只有一個形參()可省略,當函數體只有一條語句時,{}可省略,若有return,return單詞也可省略;最好都別省略;

2、遞歸:有很強抽象規律使用,階乘、斐波那契數列是典型的兩個案例;[遞歸可以使代碼更加簡捷,缺點:運行速度較慢,往往有很強抽象規律才使用]

?【1.找規律;2.找出口,防止進入死循環】

//使用過程中,只需要在函數體內寫入:return 公式? 就OK;(盡量做到靈活使用,但其確實不容易想到,后續有些地方會用到遞歸的思想,例如:算法)

3、預編譯:解決代碼執行順序問題;【聚焦點:GO全局形成、AO函數執行前形成,聚焦在變量】

js運行三部曲:?語法(語義)分析、預編譯、解釋執行;

(1).語法分析:檢查代碼是否有低級錯誤,若出現低級語法錯誤,則不執行;[關于錯誤后還有更文]

(2).預編譯:代碼執行前一刻需要進行預編譯,全局的預編譯/函數執行前的預編譯;[日常開發編寫代碼是視覺效果展示,計算機執行過程是遵循預編譯的順序執行,預編譯生成的對象就是一個空間存儲庫]

(3).解釋執行;

window全局對象的整體認知:【補充:undefined:聲明了但沒值,例如console.log(window.a);其也是對象中很特殊的一類現象,a is not defined;?壓根就不存在該變量】

window就是全局

預編譯:變量聲明提升、函數聲明整體提升都只是預編譯中的現象而已;一般遇到代碼執行問題,上述兩條就可以解決,不容易解決時創建GO、AO對象分析;[GO對象就是window對象,表示全局]

[定義變量=變量聲明+變量初始化(賦值)? var a; //變量聲明? ? a = 10; //變量初始化? ?var a=10; //定義變量?]

先形成GO對象,再形成AO對象;[代碼包含無非就是:變量、函數、語句,GO對象是在全局時候形成的,AO對象是函數執行前一刻形成的,一定要善于區分,函數輸出的變量是全局還是AO]

升華例子1:函數執行前形成的AO對象中肯定會有變量b的聲明,即使函數中該變量在if條件判斷語句中,預編譯過程中形成的對象就是后續代碼執行的依據,符合條件的提升就OK;

升華例子2:關于代碼執行順序可以get到一些點(例子1顯然返回函數、例子2因為有賦值,所以返回的是值),總之靈活應對;

【補充:如上console.log(bar);//輸出整個函數;bar:函數名/函數引用;console.log(bar()); ?- - - > 輸出函數執行結果】

----------->>>>>>生成的GO/AO對象放到什么地方?函數中里面的可訪問外面的,外面的卻不可訪問里面的這類現象的底層邏輯是什么?[之前查找變量是從GO/AO對象中查找,底層實際是從函數的作用域鏈中去查找]

4、作用域、作用域鏈精解:【聚焦點是:函數嵌套時變量的查找】

【window:全局的域;函數都有自己的獨立作用域】

每個函數都有自己的作用域鏈;產生的執行期上下文的集合形成了作用域鏈中,訪問變量的順序也遵循該鏈;里面可訪問外面,外面無法訪問里面;

一個函數只有執行的時候,產生AO對象,系統才能看到里面的東西,否則定義階段根本就看不到里面的東西;只有執行的時候才開始讀取函數里面的內容;

(1).函數也是對象(函數類對象):對象都有屬性,有些屬性我們可以直接訪問test.name/prototype;但有些屬性是不可直接進行訪問,僅供javaScript引擎讀取,[[scope]]就是其中的一個,test[[scope]];

[[scope]]:每個函數都有該屬性,稱為作用域,其內部存儲了運行期上下文的集合,這個集合呈鏈式鏈接,就是作用域鏈;

運行期上下文:也稱為執行期上下文,當函數執行的前一刻,會創建執行期上下文的內部對象,也就是預編譯時產生的GO/AO對象;[函數每次執行時都會創建新的執行期上下文(對象),所以多次調用一個函數會創建多個執行期上下文,當函數執行完畢后,所產生的執行期上下文被銷毀,這里的銷毀指代的是引用銷毀,而非代碼直接銷毀]

查找變量:從作用域鏈的頂端依次向下查找;

(2).過程剖析:

[1].函數定義的過程中函數的作用域便已經存在,即[[scope]]已經存在;首先生成GO對象,這時候a函數被定義,定義的過程中作用域鏈中 0 -->> GO對象;[函數定義的階段(GO對象生成的過程),系統根本不會關注函數體里面的內容,不會解析,生成AO對象才開始分析函數體里面的內容]

[2].GO對象形成后,開始執行代碼----->>a();--->>>函數執行前一刻形成AO對象,此時的作用域鏈中0 --->> AO對象;? 1 --->>GO對象;新形成的AO對象會在作用域鏈的頂端;[執行過程中查找變量肯定是在作用鏈中去查找,先找自己AO對象,再查找GO對象,即從作用鏈頂端以此向下查找]

[3].a函數的執行過程中,b函數開始定義(預編譯過程);定義的時候b函數會產生自己的[[scope]],其的作用域鏈環境是a函數給的,也就是a函數執行時候的環境;

[4].b函數執行中會產生自己的AO對象,然后放置到自己作用域鏈的最頂端;

[5].b函數執行結束后,銷毀自己的執行期上下文對象即AO對象(回歸到被定義的狀態,如果有二次執行,再形成新的AO對象,執行的過程中創建AO對象,執行結束后銷毀相應的AO對象即可)所謂的銷毀并非是直接把AO對象抹掉了,而是把線剪斷;[b函數作用域鏈中拿到的a函數執行過程中的作用域鏈,它們指向是相同的,只不過是生成自己的AO對象而已]

[函數內查找變量的過程:在函數自己的作用域鏈中自頂向下找,里層函數可訪問外層函數的變量,但外層函數絕對不可能訪問到里層函數的變量,外層函數作用域鏈中自己的AO與外層的環境,自己的AO對象只有里層函數的定義,定義階段系統又不解析函數體內部,所以壓根找不到函數里面的變量]

[6].b函數執行結束后,代碼中a函數也執行結束了,a函數需要銷毀自己的執行期上下文對象,回歸到被定義的狀態,銷毀AO對象的同時,b函數定義也被銷毀了,也就是b函數徹底結束了,作用域鏈中沒東西了;

[7].若是a函數再次執行,需要從新開始,創建AO對象等一系列操作同上;若是函數內嵌套了多個函數,最里面的函數作用鏈會很長,當最外面函數執行完成后,里面的函數連定義狀態都沒有了,作用鏈為空; ---->>>>>?但有特殊情況,函數執行完成后卻把里面的函數return出去了,形成閉包;

5、閉包:其是一類現象;函數嵌套中外部函數結束執行時,內部函數由于被return到了外部,依舊存活,內部函數生命周期比外部函數還長;【內部函數被保存到外部就會形成閉包,但這個過程很容易被忽視】

過程分析:[1].a函數結束執行后,return b;b函數依舊屬于被定義的狀態,環境是a函數執行時的作用域鏈,這時候b函數依舊可以操作外面函數的變量(作用域鏈的原因);[若是只是普通的在a函數外部定義的函數,由于作用域的原因,其必然是不能訪問a函數中的變量的,但閉包可以]

閉包:函數執行結束會釋放作用域鏈占用的空間,但若是函數嵌套多層,形成閉包則會導致原有作用域鏈不釋放,占用內存空間(也稱為內存泄漏【現象一致:都是占用內存,剩余內存少了】);閉包有壞處需要防治,但也有很好的應用場景來實現一些功能;

閉包的作用:

(1).實現公有變量:函數累加器;[return demo;demo的作用域鏈是add函數執行時的環境,指向的就是同一套,demo();每次指向環境沒變只是創建了新AO對象而已,所以每次操作都會改變原來的值]

(2).可以做緩存;(緩存就是存儲結構)

(3).可以實現封裝、屬性私有化;

(4).模塊化開發、防止污染全局變量;,





閉包的bug以及解決方案:[下式是經常會遇到的一種閉包情況,高頻觸發,經常會被忽視]?考慮過程中需要結合預編譯、作用域鏈、閉包的知識,開始寫GO/AO對象分析,后續盡量抽象化去分析;? ? ? myArr = [function (){console.log(i} ......] //里面10個相同的函數;myArr[j]();這時候才開始執行函數,i自身AO對象中沒有,沿著作用域鏈找test中有,此時i為10;【里面函數與test()?形成10對1的閉包】

閉包的解決方案:立即執行函數(其也是唯一的解決方案);[每循環一次立即執行函數就執行,過后銷毀,但銷毀并非是把里面的代碼給抹掉了,只是把引用抹掉了而已,循環了10次,有10個不同的立即執行函數] [立即執行函數雖然銷毀,但最終把里面的函數弄了出來,其和立即執行函數形成了閉包,j自身沒有就從立即執行函數中查找] 【里面函數與立即執行函數形成:1對1的閉包】

6.立即執行函數(也稱為函數的自執行):該函數執行過后就銷毀便不存在了;[js中提供立即執行函數來處理那些只執行一次的函數,有些函數內容巨長會占用內存][所謂的銷毀并不是直接把代碼抹掉了,而是把函數的引用抹掉]

[無論如何有的函數只執行一次(只被執行一次,我們想要其執行一次,或者執行一次返回結果的函數),我們稱之為初始化函數或初始化功能,例如開發中的數據進行初始化等,初始化后該函數就沒用了]

常規用法:[立即執行函數沒有函數名,函數名沒什么用處,寫上倒也不會報錯]

拓展(深挖底層原理):只有表達式才能被執行符號執行,執行后基本就是立即執行函數了; [function test(){}();//報錯; test();不報錯,test代表著函數體,為什么兩者結果不同??原因:test也是表達式,例如123是數字表達式];

var test = function(){ console.log('a');}();//表達式加上執行符號,執行過后就銷毀console.log(test);//undefined;

回歸到最初所提到的:(function (){} ()); (function (){})();這兩種立即執行函數形式,可以理解為外面的括號將函數聲明變為了表達式,然后被執行符號執行,變為立即執行函數;

升華例子:括號首先把函數聲明變為了表達式,然后執行if條件判斷;(開發中也沒有人這么寫)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,698評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,202評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,742評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,580評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,297評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,688評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,693評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,875評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,438評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,183評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,384評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,931評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,612評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,022評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,297評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,093評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,330評論 2 377

推薦閱讀更多精彩內容

  • ??函數表達式是 JavaScript 中的一個既強大有容易令人困惑的特性。定義函數的的方式有兩種: 函數聲明; ...
    霜天曉閱讀 829評論 0 1
  • 來源:仗劍走天涯! 關于javascript的作用域的一些總結,主要參考以上文章,加上自己的整理的理解。 近日對j...
    Michael_林閱讀 942評論 0 1
  • 原文:http://dmitrysoshnikov.com/ecmascript/javascript-the-c...
    jaysoul閱讀 482評論 0 0
  • 第3章 基本概念 3.1 語法 3.2 關鍵字和保留字 3.3 變量 3.4 數據類型 5種簡單數據類型:Unde...
    RickCole閱讀 5,147評論 0 21
  • 定義函數的方式有兩種:函數聲明和函數表達式。 函數聲明的一個重要特征就是函數聲明提升,意思是在執行代碼前會先讀取函...
    oWSQo閱讀 678評論 0 0