JavaScript: 零基礎輕鬆學閉包(1)

來源:互聯網
上載者:User

標籤:nbsp   string   ima   網上   全域   ogr   報錯   分享圖片   私人   

  • 閉包是什嗎?

初學javascript的人,都會接觸到一個東西叫做閉包,聽起來感覺很高大上的。網上也有各種五花八門的解釋,其實我個人感覺,沒必要用太理論化的觀念來看待閉包。

事實上,你每天都在用閉包,只是你不知道罷了。

比如:

var cheese = ‘乳酪‘;var test = function(){    alert(cheese);}

 

OK,你已經寫了一個閉包。

  • 函數也是一個資料類型

變數 cheese 是在全域範圍中的一個變數,當你建立了一個 test 函數,那麼,test 和 cheese 就共用一個全域範圍。

你要額外明白的一點是,在js中,函數和變數本質上是一個東西。函數也是一個資料類型。

從上面的定義中也能看出來這一點。你要是不相信的話,我們來看一下咯。

alert(cheese);alert(test);
   

讓我們再來看看 test 和 cheese各是什麼類型:

alert(typeof test);
  
alert(typeof cheese);
  

看到了吧,只是類型不同而已,他們都是資料類型。

唯一的不同點就是,函數類型的 test 可以擁有自己內部邏輯,而string類型的 cheese 只能存放一個字面值,這就是區別,僅此而已。

一目瞭然了,唯一不同的就是普通變數是字面值一樣的存在,而函數需要打個括弧才能執行而已。

你看,我現在打一個括弧:

test();
  

打了括弧,才會執行函數裡面的邏輯。

  • 範圍

讓我們回到閉包,現在將之前的代碼做一個小小的變動:

var cheese = ‘乳酪‘;var test = function(){    alert(cheese);}function test2(){    var cheese = null;    test();}test2();

 

那麼,你覺得現在 alert 出來的是 null 還是乳酪呢?

思考一下。。。

對的,彈出來的還是乳酪。

  

之前已經說過了,函數 test 和 變數 cheese 同處於一片藍天下 -- 同一個範圍。

函數 test 和 變數 cheese 共同享有的範圍叫做全域範圍,就好像地球一樣,我們所有的人都享有這個地球,能夠在這裡呼吸,吃飯,玩耍。

對test而言,他能訪問到的範圍只有它本身的閉包和全域範圍:

 Paste_Image.png

也就是說,正常情況下他訪問不到其他閉包裡的內容,在 test2 裡面定義的變數跟它沒有半毛錢關係,所以彈出來的 cheese 依舊是全域範圍裡的 cheese。

函數可以創造自己的範圍。

我們剛才定義了一個 test 函數,{ } 包裹起來的部分就形成了一個新的範圍,也就是所謂的閉包。

其實你深刻瞭解了範圍的原理後,閉包也就理解了。

就好比地球是一個全域範圍,你自己家的房子是一個函數,你的房子是私人空間,就是一個局部範圍,也就是你自己建了一個閉包!

你透過窗戶可以看見外邊的景色,比如院子裡的一棵芭蕉樹,你於是通過眼鏡觀察看到了芭蕉樹的顏色,高度,枝乾的粗細等等。

這一棵芭蕉樹相當於一個全域變數,你在自己的閉包內可以訪問到它的資料。

所以,在這個例子中,test 就是一個房子,在裡面可以通過窗戶訪問到全域範圍中的乳酪 —— 變數 cheese。

也就是說,cheese 在被 test 訪問到的時候,就進入了它的閉包。

這樣解釋,你是否覺得好理解一點呢?

現在你是否可以理解一開始我說,閉包這東西其實我們天天都在用的意思了呢?

我們給出閉包的第一個註解:

1. 閉包就是在函數被建立的時候,存在的一個私人範圍,並且能夠訪問所有的父級範圍。

回到剛才的例子:

var cheese = ‘乳酪‘;var test = function(){    alert(cheese);}function test2(){    var cheese = null;    test();}

 

在這個例子中,test 和 test2 各自享有一個範圍,對不對?而且他們互相不能訪問。比如,我在 test 中定義的一個變數,test2就無法直接存取。

var test = function(){    var i = 10;}function test2(){    alert(i);}test2();

 

像這樣,一旦執行 test2 函數,編譯就不通過,因為在 test2的閉包內,根本找不到變數 i 。它首先會在自己的閉包內尋找 i,找不到的話就去父級範圍裡找,這邊的父級就是全域範圍,很遺憾,還是沒有。這就是所謂的範圍鏈,它會一級一級往上找。如果找到最頂層,還是找不到的話,就會報錯了。

  

在這裡,還有一個需要注意的點就是:如果某一個閉包中對全域範圍(或父級範圍)中的變數進行了修改,那麼任何引用該變數的閉包都會受到牽連。

這的確是一個需要注意的地方。

舉個例子

var cheese = ‘乳酪‘;var test = function(){    cheese = ‘乳酪被偷吃了!‘}function test2(){    alert(cheese);}test();test2();

 

結果是:

 Paste_Image.png

很有趣,是不是呢?

當我們在定義一個函數,就產生了一個閉包,如果這個函數裡面又有若干的內建函式,就是閉包嵌套著閉包。

像這樣:

function house(){        var footBall = ‘足球‘;    /* 客廳 */    function livingRoom(){        var table = ‘餐桌‘;        var sofa = ‘沙發‘;        alert(footBall);    }        /* 臥室 */    function bedRoom(){        var bed = ‘大床‘;    }        livingRoom();}house(); 

 

函數house是一個閉包,裡面又定義了兩個函數,分別是livingRoom客廳,和bedRoom臥室,它們各自形成一個自己的閉包。對它們而言,父級範圍就是house。

如果我們希望在客廳裡踢足球,在livingRoom函數執行的時候,它會先在自己的閉包中找足球,如果沒找到,就去house裡面找。一層一層往上找,直至找到了為止。當然,這個例子可能不是很恰當。但起碼展示了範圍,閉包之間的聯絡。

再說明一下, 閉包就是在函數被建立的時候,存在的一個私人範圍,並且能夠訪問所有的父級範圍。因此,從理論上講,任何函數都是一個閉包!



剽悍一小兔
連結:https://www.jianshu.com/p/6f5833e261ac
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。

(轉)JavaScript: 零基礎輕鬆學閉包(1)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.