函數(shù)是js中既強大又容易令人困惑的特性,首先定義函數(shù)的方法有兩種:函數(shù)聲明和函數(shù)表達式
許多瀏覽器給函數(shù)定義了一個非標準的name屬性,console.log(functionName.name) =》 “functionName”,匿名函數(shù)的name屬性則是一個空的字符串
函數(shù)聲明的重要特征就是函數(shù)聲明提升鹅士,可以在聲明函數(shù)之前調(diào)用
在函數(shù)內(nèi)部使用函數(shù)聲明定義函數(shù)缘滥,只能創(chuàng)建局部函數(shù)
遞歸
遞歸函數(shù)是一個函數(shù)通過名字調(diào)用自身的情況下構(gòu)成的
arguments.callee是一個指向正在執(zhí)行的函數(shù)的指針轰胁,在這里等同于factorial(num-1)
閉包
閉包就是指有權(quán)訪問另一個函數(shù)內(nèi)部變量的函數(shù),通常是一個函數(shù)包含一個函數(shù)的形式朝扼,這句話大多數(shù)前端er都知道赃阀,但如何去理解閉包呢
首先要理解作用域和作用域鏈的問題,當某個函數(shù)被調(diào)用時擎颖,會創(chuàng)建一個執(zhí)行環(huán)境以及相應(yīng)的作用域鏈榛斯,然后观游,使用arguments和其他命名參數(shù)來初始化函數(shù)的活動對象,在作用域鏈中驮俗,外部函數(shù)的活動對象始終處于第二位懂缕,外部函數(shù)的外部函數(shù)的活動對象處于第三位,以此類推王凑,直至全局對象搪柑,也就是作用域鏈的終點:全局執(zhí)行環(huán)境,舉個??
后臺的每個執(zhí)行環(huán)境都有一個表示變量的對象——變量對象索烹,全局環(huán)境的變量始終存在(window)工碾,而像createComparisonFunction()函數(shù)這樣的局部環(huán)境的變量對象,只在函數(shù)執(zhí)行時存在术荤,在創(chuàng)建createComparisonFunction()函數(shù)時倚喂,會預(yù)先創(chuàng)建一個包含全局變量對象的作用域鏈,被保存在內(nèi)部的[[Scope]]屬性中瓣戚,這個對象對應(yīng)的是一個對象的列表端圈,列表中的對象僅能javascript內(nèi)部訪問,沒法通過語法訪問子库。
當調(diào)用createComparisonFunction()函數(shù)時舱权,會為函數(shù)創(chuàng)建一個執(zhí)行環(huán)境,然后通過復制函數(shù)的[[Scope]]屬性中的對象仑嗅,構(gòu)建起執(zhí)行環(huán)境的作用域鏈宴倍。作用域鏈的本質(zhì)是一個指向變量對象的指針列表,只引用但不實際包含的變量對象仓技。
通常函數(shù)執(zhí)行完成鸵贬,就是銷毀局部活動對象,但上面的??中的匿名函數(shù)的作用域鏈包含了外部函數(shù)的活動對象脖捻,所以即使外部函數(shù)執(zhí)行完畢阔逼,其局部活動對象也不會銷毀,直到匿名函數(shù)被銷毀地沮。
閉包與變量
由于作用域鏈的配置機制是一個引用嗜浮,所以閉包只能獲取包含函數(shù)中任何變量的最終值。??
由于這里沒有參數(shù)傳遞摩疑,這里的i是作用域鏈中引用的對象危融,即使它的值是基本類型,所以這里輸出10個10雷袋。
想要獲得0-9這樣的結(jié)果吉殃,可以將i作為實參傳遞給匿名函數(shù)的形參,中間是有一個復制的操作,或者使用ES6的let蛋勺,詳情參考這里
this對象
this對象是在運行時基于函數(shù)的執(zhí)行環(huán)境進行綁定的速侈,全局環(huán)境中指向window,當函數(shù)被作為某個對象調(diào)用時迫卢,指向調(diào)用的對象。this始終指向直接調(diào)用它的對象冶共。
每個函數(shù)在被調(diào)用時乾蛤,會自動取得兩個特殊的變量this和arguments,內(nèi)部函數(shù)搜索這兩個變量時捅僵,只會在活動對象里搜索家卖,并不會向上查找∶沓可以通過變量賦值的方法實現(xiàn)訪問上荡。
內(nèi)存泄漏
眾所周知,js在函數(shù)執(zhí)行完畢后會通過垃圾回收機制將函數(shù)內(nèi)部的活動對象銷毀馒闷,而閉包函數(shù)由于作用域鏈一直引用對象酪捡,所以不能銷毀,這樣就很容易造成內(nèi)存泄漏問題纳账,所以使用的時候也要記得手動銷毀逛薇。
模仿塊級作用域
js是沒有塊級作用域的概念的,所以在塊語句中定義的變量疏虫,實際是包含在函數(shù)中的變量永罚,而非語句中的變量。
私有變量
任何函數(shù)中定義的變量卧秘,都可以認為是私有變量呢袱,因為不能從外部訪問到。
有權(quán)訪問私有變量和私有函數(shù)的公有方法叫特權(quán)方法
利用私有和特權(quán)成員翅敌,可以隱藏那些不想被直接修改的數(shù)據(jù)羞福。??
靜態(tài)私有變量
通過在私有作用域中定義私有變量和函數(shù),創(chuàng)建特權(quán)方法哼御。??
這個??中的Person構(gòu)造函數(shù)和setName()和getName()方法一樣坯临,都有權(quán)訪問私有變量name,這種模式下恋昼,變量name就變成一個靜態(tài)的看靠,由所有實例共享的屬性。
模塊模式
模塊模式是為單例(只有一個實例)創(chuàng)建私有變量和特權(quán)方法液肌。??
這里的單例就是application挟炬,私有對象components數(shù)組,返回對象的getComponentCount()和registerComponent()方法都是有權(quán)訪問components對象的特權(quán)方法。
增強的模塊模式
在返回對象之前加入對其增強的代碼谤祖,這種模式適合那些單例必須是某種類型的實例婿滓,同時還必須添加某些屬性和方法對其增強情況。??
小結(jié)
本文僅是個人的看法粥喜,如有錯誤和補充凸主,歡迎指正和交流。
參考紅皮書的一些學習所得