引言
閉包這個詞對很多前端開發人員來說既熟悉又陌生,熟悉是因為很多人都用過閉包,但是用的時候不知道閉包,陌生是因為並不理解閉包,接下來這篇文章將會從多方面介紹閉包
定義
閉包是怎麼定義的呢?當函式可以記住並訪問所在的詞法作用域時,就產生了閉包,即使函式在當前詞法作用域之外執行。來看一個具體例子:
function foo () {
var a = 2
function bar () {
console.log(a)
}
return bar
}
var baz = foo()
baz() //2
複製程式碼
函式bar的詞法作用域可以訪問foo的內部作用域,並且bar在被作為返回值賦值給baz執行時,bar函式在定義時的詞法作用域以外的地方被呼叫,依然可以訪問foo函式的內部作用域變數a,這就是閉包
分析
現在讓我們來看為什麼閉包可以在定義的詞法作用域外記住並且訪問定義時的詞法作用域的變數,想要一探究竟,先來看一個簡單的例子來函式的執行過程:
function foo (a) {
console.log(a)
}
foo (a)
複製程式碼

function foo () {
var a = 2
function bar (b) {
console.log(a + b)
}
return bar
}
var baz = foo()
baz(3) //5
複製程式碼

常見問題
說到閉包相關的問題,最典型的就是變數和this指向這兩類問題。
變數
function test () {
var result = new Array()
for (var i = 0; i < 6; i++) {
result[i] = function () {
return i
}
}
return result
}
複製程式碼

function test () {
var result = new Array()
for (var i = 0; i < 6; i++) {
result[i] = (function () {
return i
})()
}
return result
}
複製程式碼
將閉包直接改成一個自執行函式,自執行函式本身是沒有變數作用域的,因此會使用外層函式的變數作用域,這樣也能達到我們想要的效果
this指向
var name = "window"
var obj = {
name: "object",
getName: function () {
return function () {
return this.name
}
}
}
console.log(obj.getName()())
複製程式碼
上面這段js程式碼的this.name的返回值是window,這是為什麼呢?按照上面寫到的,此匿名函式在執行過程中,它的作用域會包含三部分:自身的活動物件、getName函式的活動物件和全域性的變數物件,同時每個活動物件自動取得兩個特殊的變數:this和arguments,但是內部函式在查詢this時是無法直接訪問外部函式的this變數,因此會沿著作用域鏈去查詢全域性變數中繼續查詢,如果想要取外部函式中的this取值也很簡單,只需要向下面程式碼這樣:
var name = "window"
var obj = {
name: "object",
getName: function () {
var that = this
return function () {
return that.name
}
}
}
console.log(obj.getName()())
複製程式碼
將this賦值給一個變數,內部函式是可以訪問外部函式變數的,這樣就解決了
總結
閉包是一個容易混淆不清的概念,這篇文章對閉包的定義、執行、常見問題做了簡單的介紹,希望通過這篇能對大家理解和使用閉包有所幫助。如果有錯誤或不嚴謹的地方,歡迎批評指正,如果喜歡,歡迎點贊。