首頁  >  文章  >  web前端  >  什麼是 Javascript 的閉包

什麼是 Javascript 的閉包

小云云
小云云原創
2017-11-20 15:28:541161瀏覽

什麼是閉包?

閉包是什麼?閉包是Closure,這是靜態語言所不具有的一個新特性。但是閉包也不是什麼複雜到不可理解的東西,簡而言之,閉包就是:閉包就是函數的局部變數集合,只是這些局部變數在函數回傳後會繼續存在。閉包就是是函數的「堆疊」在函數返回後並不釋放,我們也可以理解為這些函數堆疊並不在棧上分配而是在堆上分配,當在一個函數內定義另一個函數就會產生閉包。

閉包= 函數內部建立的函數(或簡稱內部函數) + 函數建立時所處環境資訊

所以閉包並不等於匿名函數,雖然也有人稱這些在函數內部建立的函數為閉包函數,但是我覺得其實不準確。

我們看一下下面這段程式碼:

function init() {
    var name = "Zilongshanren"; // name 是在 init 函数里面创建的变量
    // displayName() 是一个内部函数,即一个闭包。注意,它不是匿名的。
    function displayName() {
        console.log(name);
    }
    //当 displayName 函数返回后,这个函数还能访问 init 函数里面定义的变量。
    return displayName;
}
var closure = init();
closure();
Zilongshanren
undefined

displayName 是一個在 init 函數內部創建的函數,它攜帶了 init 函數內部作用域的所有信息,例如這裡的 name 變數。當 displayName 函數傳回的時候,它本身就攜帶了當時創建時的環境訊息,也就是 init 函數裡面的 name 變數。

閉包有什麼作用?

在理解什麼是閉包之後,接下來你可能會問:這東西這麼難理解,它到底有什麼用啊?

因為在 Js 裡面是沒有辦法建立私有方法的,它不像 java 或 C++有什麼 private 關鍵字可以定義私有的屬性和方法。 Js 裡面只有函數可以創造出屬於自身的作用域的對象,Js 並沒有塊作用域!這個我後面會再寫一篇文章詳細介紹。

程式老鳥都知道,程式寫得好,封裝和抽像要運用得好!不能定義私有的屬性和方法,意味著封裝和抽像根本沒用。 。 。

無法定義私有的東西,所有變數和函數都 public 顯然有問題, Global is Evil!

閉包是我們的救星!

我們看一下下面這段程式碼:

var makeCounter = function() {
    var privateCounter = 0;
    function changeBy(val) {
        privateCounter += val;
    }
    return {
        increment: function() {
            changeBy(1);
        },
        decrement: function() {
            changeBy(-1);
        },
        value: function() {
            return privateCounter;
        }
    }
};
var counter1 = makeCounter();
var counter2 = makeCounter();
console.log(counter1.value()); /* Alerts 0 */
counter1.increment();
counter1.increment();
console.log(counter1.value()); /* Alerts 2 */
counter1.decrement();
console.log(counter1.value()); /* Alerts 1 */
console.log(counter2.value()); /* Alerts 0 */
0
2
1
0
undefined

這裡面的 privateCounter 變數和 changeBy 都是私有的,對於 makeCounter 函數外部是完全不可見的。這樣我們透過 makeCounter 產生的物件就把自己的私有資料和私有方法全部隱藏起來了。

這裡有沒有讓你想到點什麼?

哈哈,這不就是 OO 麼?封裝資料和操作資料的方法,然後透過公共的介面呼叫來完成資料處理。

當然,你也許會說,我用原型繼承也可以實作 OO 呀。沒錯,現在大部分人也正是這麼幹的,包括我們自己。不過繼承這個東西,在理解起來總是非常困難的,因為要理解一段程式碼,你必須要理解它的所有繼承鏈。如果一旦程式碼出 bug 了,這將是非常難調試的。

扯遠了,接下來,讓我們看看如何正確地使用閉包。

如何正確地使用閉包?

閉包會佔用內存,也會影響 js 引擎的執行效率,所以,如果一段程式碼被頻繁執行,那麼要謹慎考慮在這段程式碼裡面使用閉包。

讓我們來看一個創建物件的函數:

function MyObject(name, message)
 {    this.name = name.toString();  
   this.message = message.toString();   
    this.getName = function()
     {        return this.name;    };   
      this.getMessage = function() 
      {        return this.message;    };}
      var myobj = new MyObject();
var myobj = new MyObject();

每一次被呼叫產生一個新物件的時候,都會產生兩個閉包。如果你的程式裡面有成千上萬個這樣的 MyObject 對象,那麼就會多出很多記憶體佔用。

正確的做法應該是使用原型鏈:

function MyObject(name, message) {
    this.name = name.toString();
    this.message = message.toString();
}
MyObject.prototype.getName = function() {
    return this.name;
};
MyObject.prototype.getMessage = function() {
    return this.message;
};
var myobj = new MyObject();

現在MyObject 原型上面定義了兩個方法,當我們透過new 去建立物件的時候,這兩個方法只會在原型上面存有一份。

閉包的效能如何?

閉包也是一個函數,但是它存儲了額外的環境信息,所以理論上它比純函數佔用更多的內存,而且 Js 引擎在解釋執行閉包的時候消耗也更大。不過它們之間的效能差異在 3%和 5%之間(這是 Google 上得到的數據,可能不會太準確)。

但是,閉包的好處一定是大大的。多使用閉包和無狀態編程,讓 Bug 從此遠離我們。

了解閉包,你就能理解大部分 FP 範式的 Js 類別庫及其隱藏在背後的設計想法。當然只有閉包還不夠,你還需要被 FP 和無狀態,lambda calculus 等概念洗腦。

關於js閉包希望大家學完本篇內容之後就有所掌握。

相關推薦:

JS中關於閉包的簡單解釋

js中閉包和類別如何理解

對js閉包的簡單理解

以上是什麼是 Javascript 的閉包的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
上一篇:帶你吃透正則下一篇:帶你吃透正則