1、定義函數的兩種方式:
1)函數聲明:存在函數聲明提升
2)函數表達式:使用前必須先賦值;匿名函數(拉姆達函數)
2、關于遞歸:
arguments.callee()指向正在執行的函數的指針(嚴格模式下會報錯,嚴格模式下改用函數表達式)
3、閉包:有權訪問另一個函數作用域中的變量的函數
創建閉包的常見方式:在一個函數中創建另一個函數
來更通俗地理解一下:
我們用“變量對象”這個名詞來表示執行環境
全局變量的“變量對象”一直存在
函數的“變量對象”只有在執行的時候才存在
創建函數的時候,會創建包含全局“變量對象”的作用域鏈
調用函數的時候,有了執行環境,作用域鏈就加上了該函數的“變量對象”
作用域鏈的組成:
arguments和其他命名參數的值初始化的活動對象------>
外部函數的活動對象------>
外部函數的外部函數的活動對象------>
..........------>
全局執行環境
作用域本質上是:指向變量對象的指針列表
外部函數執行完以后,作用域鏈就會被銷毀,但是直到包含的匿名函數銷毀后,他的活動對象才會被銷毀。
由于閉包攜帶包含它的函數的作用域,占用內存更多,因此應該慎重考慮使用它。
4、匿名函數的執行環境具有全局性,因此this總是指向window
解決辦法:在創建閉包,也就是匿名函數之前,就把this的值轉移賦值給另一個變量(例如that)
5、比較重要的一點:匿名函數之模仿塊級作用域(私有作用域)
(function () {}) ();
避免向全局作用域中添加過多的變量和函數,團隊合作中很容易導致命名沖突。
6、私有變量包括函數的參數、局部變量、函數內部定義的其他函數
可以利用閉包來創建私有變量的共有方法(特權方法)
1)利用構造函數,缺點是對于每一個新實例都要創建一組同樣的方法組
2)靜態私有變量:利用了塊級作用域和原型模式,達到了方法復用,但是實例們沒有屬于自己的私有變量
*sp1)為單例創建特權方法:返回對象(特權方法在這)的匿名函數。
補充一下:js通過對象字面量來創建單例,單例通常都是作為全局對象存在的。
*sp2)適合特定類型----增強的模塊模式:先new再返回一個對象(帶有公共屬性和特權方法)