阮一峰關於 Javascript 中閉包的解讀是否正確?

來源:互聯網
上載者:User
阮一峰有一篇關於javascript 閉包的科普文章:
學習Javascript閉包(Closure)

感覺講的挺好的,考慮到之前被樸靈噴的很慘,所以開始懷疑博文中的講解是否正確。

博文部分觀點:
1. 我的理解是,閉包就是能夠讀取其他函數內部變數的函數。
2.由於在Javascript語言中,只有函數內部的子函數才能讀取局部變數,因此可以把閉包簡單理解成"定義在一個函數內部的函數"。
3.閉包可以用在許多地方。它的最大用處有兩個,一個是前面提到的可以讀取函數內部的變數,另一個就是讓這些變數的值始終保持在記憶體中。

回複內容:

某些說法的確不嚴謹,但也沒必要噴。
比如:
函數內部聲明變數的時候,一定要使用var命令。如果不用的話,你實際上聲明了一個全域變數!
不使用 var 等於沒有聲明變量,而是相當於訪問了 window 的屬性。
和在 window 下聲明變量的區別在於,訪問 window 的屬性創建的變量可以 delete,在全域範圍下直接聲明的變量不可以 delete。

window.b = "hi";b; // "hi"delete b; // trueb; // ReferenceError: b is not defined(function(){c = "hi"}());c; // "hi"delete c; // truec; // ReferenceError: c is not definedvar a = "hi";a; // "hi"delete a; // falsea; // "hi"
以 “某些說法的確不嚴謹,但也沒必要噴。” 開頭的匿名回答是對的。

關於閉包的概念,其實就是來自函數式語言。

var a = function () {  var test = {};  setTimeout(function () {    console.log(test);  }, 1000);}
阮一峰的文章是他的學習筆記,並不保證全部正確,因為只是他的理解,而且這篇文章是他09年時寫的,可能那時候他的水平比現在還差一些。
不過他文章的含金量還是比較高的,同時因為是他的學習筆記,所以我們讀起來也通俗易懂。很多初學者可以從阮一峰的文章向高水平進階,但是通俗易懂的東西一般會存在不嚴謹的情況。嚴謹的文章非常好,但是不利於初學者理解。為什麼這麼說呢,嚴謹的概念會包含很多對初學者來說十分模糊的專業術語,比如上面答主cosx所提到的:閉包是由函式和與其相關的參照環境組合而成的實體。(原句可能是:A "closure" is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).)如果是初學者,我相信一看到函式、相關環境等字眼,則直接懵逼。
但是阮一峰說:閉包就是能夠讀取其他函數內部變數的函數。這麼解釋,只要動動腦,應該可以大概理解閉包是什麼東西了。即便這句話很不嚴謹。
所以說阮一峰的文章依然值得看,他的文章可以把你帶入一個領域,但是想要正確的認識這個領域,你依然需要去看書,這也是網路文章與實體書的區別。
----------------------------------------------
想要徹底正確的理解閉包,還是要看cosx、樸靈的回答,但是要攢夠基礎知識。閉包就是在函數中 使用未在函數中定義但在函數所處上下文有效變數(標識符)與函數本體的集合。還是嚴謹一點比較好閉包確實是js最難理解的東西了,閉包的本質可以說是範圍鏈形成的
要理解閉包,必須要理解這幾個概念
1.詞法範圍
2.執行內容
3.使用中的物件
4.scope屬性

假設如下代碼
function A(arg1){
var v1=1;
var b=function B(){ //執行到這一行定義了函數B,用運算式避免變數提升問題
}
}
A();
一個函數B在定義(聲明)時,它在代碼樹上的上一層函數A此時正處於運行狀態(執行內容指向函數A),此時函數B會產生一個scope屬性(函數本質也是對象,可以定義屬性),B.scope是一個數組,但是通過代碼是訪問不到的,通過chome調試面板可以看到,留心的同學可以發現,push了A的使用中的物件(如果A有上一層函數,會依次push進去),此時B.scope=[{v1:1}],當前函數的使用中的物件包含了一個函數體內所有var聲明的變數,在函數B內部尋找變數時優先尋找B的使用中的物件中的變數,如果沒有,則遍曆scope屬性數組中的父級函式活動對象。

因為只有在運行時的代碼才能聲明函數,每一個函數在聲明時,父級函數必然處於執行狀態,遞迴思考一下,可知範圍鏈完全由函數編寫時的嵌套順序所決定,這就是詞法範圍的含義,看一個函數的範圍,只要靜態分析代碼樹的結構就行了。
所謂的範圍鏈,其實就是隱含的scope屬性一級級的向上引用上一層函數的變數對象,變數對象的尋找過程,原理上和對象的屬性通過__proto__原型鏈尋找過程差不多。閉包就是打入敵人內部的間諜,通過他你可以接觸敵人對外封鎖的資訊。再提一些 個人認為有誤導性的地方!

Javascript語言的特殊之處,就在於函數內部可以直接讀取全域變數。
搞的好像其他物件導向的語言不能似的。

另一方面,在函數外部自然無法讀取函數內的局部變數。
根本沒有提到關鍵,為什麼不能讀取內部變數?函數在執行完後會銷毀其內部環境這個就沒提及。

第六個思考題:
如果你能理解下面兩段代碼的運行結果,應該就算理解閉包的運行機制了。
var name = "The Window";  var object = {    name : "My Object",    getNameFunc : function(){      return function(){        return this.name;      };    }  };  alert(object.getNameFunc()());
什麼是閉包?

閉包並不是什麼新奇的概念,它早在進階語言開始發展的年代就產生了。閉包(Closure)是詞法閉包(Lexical Closure)的簡稱。對閉包的具體定義有很多種說法,這些說法大體可以分為兩類:

  • 一種說法認為閉包是符合一定條件的函數,比如參考資源中這樣定義閉包:閉包是在其詞法上下文中引用了自由變數(注1)的函數。
  • 另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。比如參考資源中就有這樣的的定義:在實現深約束(注2)時,需要建立一個能顯式表示引用環境的東西,並將它與相關的子程式捆綁在一起,這樣捆綁起來的整體被稱為閉包。

這兩種定義在某種意義上是對立的,一個認為閉包是函數,另一個認為閉包是函數和引用環境組成的整體。雖然有些咬文嚼字,但可以肯定第二種說法更確切。閉包只是在形式和表現上像函數,但實際上不是函數。函數是一些可執行檔代碼,這些代碼在函數被定義後就確定了,不會在執行時發生變化,所以一個函數只有一個執行個體。閉包在運行時可以有多個執行個體,不同的引用環境和相同的函數組合可以產生不同的執行個體。所謂引用環境是指在程式執行中的某個點所有處於活躍狀態的約束所組成的集合。其中的約束是指一個變數的名字和其所代表的對象之間的聯絡。那麼為什麼要把引用環境與函數組合起來呢?這主要是因為在支援嵌套範圍的語言中,有時不能簡單直接地確定函數的引用環境。這樣的語言一般具有這樣的特性:

  • 函數是一階值(First-class value),即函數可以作為另一個函數的傳回值或參數,還可以作為一個變數的值。
  • 函數可以嵌套定義,即在一個函數內部可以定義另一個函數。
1&2:閉包是用來描述那個函數能夠訪問那個變數的這種能力的。而不是那個函數也不是那個變數。也就是一個函數能訪問其詞法範圍之外的變數的能力。
3:永久儲存在記憶體?只是將對象的生命延長到和使用它的函數一致。如果所有使用它的函數都被回收了,這個變數也就回收了。(好吧,在實踐中,這屬於鑽牛角尖了,而且還要看JS引擎如何?)

閉包在JS中的作用:
隱藏私人變數
將額外參數傳遞給運行時產生的函數 (因為你產生的函數會被別人調用,比如回呼函數,毫無疑問函數的參數個數和次序已定,但你的函數確實需要更多資訊)

需要注意的問題:
一個變數進入閉包後,會被複製到堆中,所有對該變數的使用都解析為引用這個堆中的變數。所以,使用這個變數的所有函數都會讀取到最新的值,而不是你建立該函數時的值。

其實 專業一點的JS書中都有解釋。
  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.