##1. 函數表達式與函數聲明的區別##
函數聲明有「提升」(hoisting)的特性,而函數表達式沒有。也就是說,函數聲明會在加載代碼時被預先加載到 context 中,而函數表達式只有在執行表達式語句時才會被加載
##2. 閉包##
有權訪問另一個函數作用域中的變量的函數。閉包可以訪問另一個作用域中的變量,因此閉包得到的變量值是最終值,而不是該變量在某一時刻的值,有一個很經典的例子:
function createFuns(){
var result = new Array();
for(var i = 0;i < 10;i++){
result[i] = function(){
return i;
};
/*
result[i] = function(arg){
return function(){
return arg;
}
}(i);//此處匿名函數立即執行的 () 可以省略,因為 function 在等號右邊出現,不存在歧義(一般形式是 (function(){})())
*/
}
return result;
}
createFuns 函數返回一組函數,這些函數執行結果都是 10(閉包得到的變量值是最終值),但註釋中的方式返回函數的執行結果就是 i 的當前值,因為是值傳遞
##3. 函數表達式中的 this##
內部函數無法直接訪問外部函數中的 this 和 arguments 對象,因為內部函數在搜索這兩個變量時,只會搜索到其活動對象為止
P.S. 活動對象是作用域鏈的實體,作用域鏈是抽象概念,而活動對象就是這個概念的具體實現。其實作用域鏈映射到代碼裡就是變量對象鏈條,又扯出了變量對象,不用怕,一點都不複雜:
執行環境(context)中定義的所有變量和函數都保存在變量對象中,如果執行環境是一個函數,那就把函數的活動對象當作變量對象,並作為變量對象鏈的一環,也就是作用域鏈的一環。
一開始函數的活動對象只有一個屬性——arguments 對象,每在函數內部聲明一個自定義屬性,就給該函數的活動對象添加一個屬性。。。
嗯,扯了這麼多,其實就一句話:this 就是活動對象/變量對象的引用。
如果還不大明白,請參考 前輩的博文,順便推薦這位前輩的其它博文,關於 js 的都很不錯
##4. 重複聲明變量##
不會引起語法錯誤,會自動忽略多餘的聲明,但聲明同時的初始化操作會被執行,例如:
var x = 1;
var x = 2;//var 聲明被忽略,所以不報錯,但賦值會被執行
alert(x);//2
##5. 實現塊級作用域的思路##
聲明一個匿名函數並立即調用,那麼匿名函數內部就是塊級作用域。具體實現:
(function(){/*塊級作用域*/})();
注意:需要用圓括號來消除函數表達式與函數聲明的歧義(從解釋器的角度看就是這樣),因為函數聲明後面不能直接跟圓括號,而函數表達式可以。
P.S. 示例中的代碼只是一種實現 IIFE 的方式,還有幾種,具體請參考 [javascript]IIFE 立即執行的函數表達式,這篇博文給出了詳細的對比
##6. 私有變量##
函數內部用 var 或者 function 聲明的變量是私有變量。(實例無法直接訪問,可以通過定義公有函數來提供訪問接口)
而用 this.attr = value; 方式聲明的變量是公有變量。(實例可以直接訪問)
##7. 閉包、匿名函數、內部函數、內部匿名函數的區別##
-
閉包:有權訪問另一個函數作用域中的變量的函數
-
匿名函數:沒有名字的函數表達式
-
內部函數:在函數內部聲明的函數,也就是閉包
-
內部匿名函數:在函數內部聲明的匿名函數,當然,也是閉包
P.S. 濫用閉包可能會佔用大量記憶體,閉包之所以能夠訪問外層函數作用域中的變量,是因為閉包的活動對象持有外層函數活動對象的引用
只有在閉包被銷毀後,外層函數中的變量才能被銷毀,不能及時銷毀,所以可能佔用大量記憶體
##8. 執行函數的整個過程##
-
創建執行環境 context,context 有內部屬性 [[Scope]]
-
更新作用域鏈 ScopeChain
-
創建活動對象
-
初始化活動對象的 this, arguments, 形參等各個屬性
-
執行函數體
-
銷毀活動對象(存在閉包時無法銷毀)
-
更新作用域鏈
##9.js 單例模式與模組模式##
-
單例模式:創建只有一個實例的對象的一種模式,說白了,模式就是方法,設計模式就是前輩總結出來的好方法。js 中實現單例模式尤其簡單:
var singleton = {attr1: value1, attr2: value2};
沒錯,就是對象字面量,其實就是創建了匿名對象,不知道構造函數的名字,當然無法創建第 2 個實例了
-
模組模式:道格拉斯提出的用來增強單例的方法,可以給單例添加私有屬性和公有屬性(有時候也叫特權屬性,表示有權修改私有屬性的屬性),例如:
var singleton = function(){ //私有屬性 var privateStr = 'secret'; function addPrefix(){ privateStr = 'this is my ' + privateStr; } //公有屬性(特權屬性) return{//返回一個匿名對象 getStr : function(){ addPrefix(); return privateStr; } }; }();//又是匿名函數立即執行 alert(singleton.getStr());
P.S. 如果不需要單例,只要保護私有屬性的話,可以這樣做:
function Cat(){
//私有屬性
var privateStr = 'secret';
function addPrefix(){
privateStr = 'this is my ' + privateStr;
}
//公有屬性(特權屬性)
this.getStr = function(){
addPrefix();
return privateStr;
}
}
var obj = new Cat();
alert(obj.getStr());
參考資料###
-
this 到底是個啥東西:前輩的博文
-
匿名函數立即執行的幾種方式:[javascript]IIFE 立即執行的函數表達式
暫無評論,快來發表你的看法吧