天天看點

js閉包的應用前言簡單回顧閉包的應用小結補充

前言

之前發了一篇文章,寫了一些對于閉包的了解。現在補上閉包的應用篇,(很慚愧因為嚴重的拖延症一直拖到現在)。本文主要分享一些常見的閉包用法和分析,也希望能增加對閉包的了解。

簡單回顧

在之前的文章裡,講解了閉包的原理,如果忘記了可以點選這裡再看一下,在這裡我們簡單回顧一些知識點:

  • 閉包的本質是一個函數
  • 閉包可以通路函數内部變量
  • 閉包的存在會使内部變量保留在記憶體中

閉包的應用

閉包常見的用法,就将圍繞這些特點展開:

1.模仿塊級作用域

首先簡單舉個例子來,解釋一下什麼是塊級作用域:

function A(num) {
    for (var i = 0; i < num; i++) {
      num++;
    }
    console.log(i)
  }
           

在這個簡單的函數中,

變量i

是在

for

循環中定義的,如果是在C++或者Java中,這樣定義的變量,一旦循環結束,變量也就随之銷毀,i的作用範圍隻在循環這個小塊,就稱為塊級作用域。在javascript中,沒有這樣的塊級作用域,前面一篇文章已經提到,變量是定義在函數的活動對象中的,是以,從定義

i

開始,在函數内部可以随時通路它。

這樣的壞處顯而易見:由于javascript不會告訴你變量是否已經被聲明,容易造成命名沖突,如果是在全局環境定義的變量,就會污染全局環境,是以可以利用閉包特性來模拟塊級作用域。不過在此之前要先介紹另一個知識點:匿名立即執行函數。如果已經比較熟悉的同學可以直接跳過這一塊:

匿名立即執行函數

首先舉個例子(我比較喜歡舉例,感覺看例子比較更容易了解):

var helloWorld = function(){
    alert('Hello world')
}
helloWorld();//執行函數
           

上面的簡短代碼一共就做兩件事:1.定義了一個匿名函數并指派給

helloWorld

;2.在

helloWorld

後面加括号表示調用函數,是以 匿名函數如果直接執行,是不是應該這樣寫:

function(){
    alert('Hello world')
}()
           

這樣的寫法會報錯,因為在javascript中,function是函數聲明的标志,不允許在後面直接加括号,而應該寫成這樣:

(function(){
    //函數體
    alert('Hello world')
})()
           

也就是把聲明部分加括号即可,加了括号以後,這一段代碼就相當于執行了裡面的函數體部分,但是此時内部的變量已經不能被外部通路,請看下面詳細樣例

具體實作

現在我們講模拟塊級作用域的具體步驟,假設還是針對前面的

A函數

,如果我們想讓i變量隻有塊級作用域,可以這樣寫:

function A(num) {
    //核心代碼
   (funnction(){
    for(var i = 0; i<num; i++) {
      num++;
    }
    })()
    //核心代碼結束
    console.log(i)//underfined
  }
           

注意看核心代碼部分,我們用剛剛講到的匿名自執行函數在内部形成了一個閉包,這個閉包在哪呢?一直強調,閉包的本質是函數,其實在這裡閉包就是那個匿名函數,這個閉包可以到

函數A

内部的活動變量,又能保證自己内部的變量在自執行後直接銷毀,這個應該不難了解了

優點分析

這種寫法的經常用在全局環境中,可以避免添加太多的全局變量和全局函數,特别是多人合作開發的時候,可以減少是以産生的命名沖突等,避免污染全局環境。

2.存儲變量

我們知道閉包的另一個特點是可以儲存外部函數的變量,原理是基于javascript中函數作用域鍊的特點,内部函數保留了對外部函數的活動變量的引用,是以變量不會被釋放(這一塊沒有了解清楚的請看前一篇文章,裡面講的比較詳細),然後我們再來愉快地舉例子:

function B(){
    var x = 100;
    return {
        function(){
            return x
        }
    }
}
var m = B()//運作B函數,生成活動變量 x被m引用
           

這是前文介紹過的一個最簡單的閉包例子,我們運作

B函數

,傳回值就是B内部的匿名函數,此時m引用了變量x,是以B執行後x不會被釋放,利用這一點,我們可以把比較重要或者計算耗費很大的值存在x中,隻需要第一次計算指派後,就可以通過m函數引用x的值,不必重複計算,同時也不容易被修改

優點分析

這種寫法可能會用在把一些不經常變動,但是計算比較複雜的值儲存起來,就可以節省每次通路的時間。

3.封裝私有變量

javascript中沒有私有成員的概念,我們可以把函數當做一個範圍,函數内的變量就是私有變量,在外部無法引用,比如:

function C(a,b){
    var c = a - b ;
    return c
}
           

在這個函數中,a b c都是私有變量,在外部無法訪,利用閉包的特點,我們可以就可以建立可以通路私有變量的方法:

function Person(){
    var name = 'default';
    this.getName:function(){
        return name;
    }
    this,setName:function(value){
        name = value;
    }
}
console.log(Person.getName())//default
console.log(Person.setName('mike'))
console.log(Person.getName())//mike
           

在這個例子中,設定了兩個閉包函數來操作

Person函數内部的name變量

,除了這兩個函數,在外部無法再通路到name變量,name也就相當于是私有成員。在這個例子中,我們用的是在構造函數中定義公有方法,對于所有的Person執行個體,都分别建立了新的辦法,當然還可以使用其他形式來避免這個問題,要涉及到建立對象模式的一些知識,在這裡說明怕反而增加了閉包的了解難度,之後在寫對象和繼承的時候再提到(下一次更新一定不會這樣久了QAQ)。

小結

關于閉包的主要主要應用就講到這裡,本文中很多知識點與上一篇文章有關,又因為釋出相隔時間比較長(我的鍋),建議大家可以先看看上一篇複習一下,這篇相對來前一篇容易了解,而且在舉例過程盡量沒有加入其它的疑難知識點,希望能對看到的人有所幫助。以上内容屬于個人見解,如果有不同意見,歡迎指出和探讨。同時,碼字不易請尊重作者的版權,轉載請注明出處,如作商用,請與作者聯系,感謝!

補充

如果看完對您有幫助,順手點個推薦呗~