理解javascript閉包


1.閉包是什么

官方解釋:閉包是一個擁有很多變量和綁定了這些變量的環境的表達式(其實就是函數),因而這些變量也是該表達式的一部分。這個定義雖然太學術,但是告訴我們兩個信息:

1)閉包是一個函數

2)函數中有很多變量

上面兩個是構成閉包的兩個主要條件。

下面我們用通俗的話來解釋一下:js中的所有函數都是閉包(因為函數中的局部變量只能函數內部訪問),但是嵌套函數產生的閉包更加強大,也是我們現在所探討的閉包。

如果上面的解釋還不夠通俗,下面的終極解釋我想你一定能夠看懂:

有一個函數a,函數a中嵌套了一個函數b,如果函數b被函數a外部的一個變量引用,就創建了一個閉包。

下面我們來看看具體如何通過代碼來創建閉包,以加深上面概念的理解。

2.創建閉包

在創建閉包之前,首先要明白兩個概念,一個是變量的作用域,一個事js中的作用域鏈,第一點我們簡單說一下,第二點自己去查資料。

在Js中變量根據作用域的不同可以分為全局變量和局部變量(事實上很多語言都是這樣),在js中,如果一個變量沒有定義在任何函數中,則為全局變量;相對應的,定義在函數中的變量就是局部變量,但是如果函數中變量在聲明時沒有使用var關鍵字,則其仍然會稱為全局變量。我們來看例子。

 

function f() {
            a = 1;//沒有使用var,所以在函數外部也可以訪問
        }
        f();
        alert(a);

  

下面我們看看如何創建閉包,看下面的函數

 

 

     function f1() {
            var a = 10;
            a++;
            alert(a);
        }
        var func1 = f1();
        func1;
        func1;

 

希望你能猜對上面代碼的運行結果,只輸出一個11。在函數f1的外部創建了變量func1,然后指向由函數f1的返回值。當執行完代碼func1之后,這個對象就沒有引用了,所以會被垃圾回收,對象中的變量a同樣也會被回收;所以當再次執行func1時就不會有輸出了。

 

從上面的代碼,希望你能明白這樣一個道理:js中是有垃圾回收機制的。當一個對象沒有變量引用的時候,這個對象就會被回收。

再來看下面的代碼:

 

function f1() {
            var a = 10;
            function f2() {
                a++;
                alert(a);
            }
            return f2;
        }
        var func1 = f1();
        func1();
        func1();

  

上面代碼的輸出結果為11,12。

 

執行完第一句func1()之后,對象應該被回收,第二句func1();應該沒有輸出猜對呢,這是為什么呢?

我們來分析一下。

首先看var func1=f1();這行代碼執行之后,func1是什么。在函數f1中返回的是函數f2,所以func1的值其實是函數f2。按理說當執行完這行代碼之后,函數f1的使命已經完成,應該被垃圾回收才是,你們變量a也會被清除,但是執行代碼func1()之后的結果居然為11,這說明函數f1中的變量a沒有被清除,那么肯定函數f1也沒有被垃圾回收。這是為什么?

我們前面說過,一個對象如果被垃圾回收的條件是什么,那就是沒有變量引用這個對象。我們來看看上面的代碼。函數f2中對函數f1中的變量a進行++操作,也就是說在函數f2中引用了函數f1中的變量,也就是函數f2引用了函數f1。而代碼var func1=f1();其實是將函數f2返回給變量func1,也就是說變量func1引用了函數f2,而函數f2由引用了函數f1,這種間接引用的結果就是函數f1一直被變量引用着,所以一直無法被垃圾回收。

上面的情況就是閉包,我們再回顧一下閉包的定義:如果函數a中的嵌套函數b被函數a外部的變量引用,就創建了閉包。

綜合上面的討論,我們可以看出閉包的作用是什么

3.閉包的作用

1)變量的安全性:我們無法在函數f1的外部直接訪問其局部變量a,只能通過函數f2來訪問,而在函數f2中我們可以寫代碼進行安全性的控制,這是不是和c#中類的屬性很像。所以我們可以將函數f2看成是函數f1的一個屬性,這個屬性只有setter方法,而將局部變量a看成是函數f1的私有字段,只能通過公共屬性f2才能訪問f1中的私有字段a。

2)讓變量的值始終保存在內存中。這個已經非常清晰了,通過閉包,函數f1中的變量a沒有被回收,而是一直保存在內存中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM