雖然工做有兩年多了,可是對於閉包這個概念一直不甚解,查過一些博客和視頻,大概有三種說法:html
各有各的說法,也不知道到底信誰的,後來想到書是最有權威的,尤爲是經典。閉包
JavaScript語言精粹對閉包是這樣描述的:函數
它首先列舉了一個例子:spa
//建立一個名爲 quo 的構造函數 //它構造出帶有 get_status 方法和 status 私有屬性的一個對象 var quo = function (status) { return { get_status:function () { return status; } }; }; //構造一個 quo 實例 var myQuo = quo("amazed"); document.writeln(myQuo.get_status());
這個 quo 函數被設計成無須再前面加上new 來使用, 因此名字也沒有首字母大寫。當咱們調用 quo 時,它返回包含get_status 方法的一個新對象。該對象的一個引用保存在myQuo中。即便quo 已經返回了,可是get_status 方法仍然享有返回 quo 對象的 status 屬性的特權。get_status 方法並非訪問該參數的一個副本,它訪問的就是該參數自己。這是可能的,由於該函數能夠訪問它被建立時所處的上下文環境。這就是閉包。設計
JavaScript語言精粹對閉包是舉例說明,好像閉包就是函數嵌套並返回子函數,這也是大多數人的理解。可是好像有點片面,而JavaScript高級程序設計就說的更詳細了:code
閉包是指有權訪問另外一個函數做用域中的變量的函數。建立閉包的常見方式,就是在一個函數內部建立另外一個函數,仍之前面的 createComparisonFunction() 函數爲例,注意加粗的代碼。視頻
function createComparisonFunction(propertyName) { return function (object1, object2) { var value1 = object1[propertyName]; var value2 = object2[propertyName]; if(value1 < value2){ return -1; } else if(value1 > value2){ return 1; } else { return 0; } }; }
在這個例子中,突出的那兩行代碼是內部函數(一個匿名函數)中的代碼,這兩行代碼訪問了外部函數中的變量 propertyName 。即便這個內部函數被返回了,並且是在其餘地方被調用了,,但它仍然能夠訪問變量 propertyName 。之因此還可以訪問這個變量,是由於內部函數的做用域鏈中包含createComparisonFunction() 的做用域。要完全搞清楚其中的細節,必須從理解函數被調用的時候都會發生什麼入手。htm
第4章介紹了做用域鏈的概念。而有關如何建立做用域鏈以及做用域鏈有什麼做用的細節,對完全理解閉包相當重要。當某個函數被調用時,會建立一個執行環境(execution context)及相應的做用域鏈。而後,使用 arguments 和其餘命名參數的值來初始化函數的活動對象(activation object)。但在做用域鏈中,外部函數的活動對象始終處於第二位,外部函數的外部函數的活動對象處於第三位,......直到做爲做用域鏈終點的全局執行環境。對象