閉包這個詞對不少前端開發人員來講既熟悉又陌生,熟悉是由於不少人都用過閉包,可是用的時候不知道閉包,陌生是由於並不理解閉包,接下來這篇文章將會從多方面介紹閉包前端
閉包是怎麼定義的呢?當函數能夠記住並訪問所在的詞法做用域時,就產生了閉包,即便函數在當前詞法做用域以外執行。來看一個具體例子:面試
function foo () {
var a = 2
function bar () {
console.log(a)
}
return bar
}
var baz = foo()
baz() //2
複製代碼
函數bar的詞法做用域能夠訪問foo的內部做用域,而且bar在被做爲返回值賦值給baz執行時,bar函數在定義時的詞法做用域之外的地方被調用,依然能夠訪問foo函數的內部做用域變量a,這就是閉包bash
如今讓咱們來看爲何閉包能夠在定義的詞法做用域外記住而且訪問定義時的詞法做用域的變量,想要一探究竟,先來看一個簡單的例子來函數的執行過程:閉包
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
}
複製代碼
將閉包直接改爲一個自執行函數,自執行函數自己是沒有變量做用域的,所以會使用外層函數的變量做用域,這樣也能達到咱們想要的效果ui
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取值也很簡單,只須要向下面代碼這樣:this
var name = "window"
var obj = {
name: "object",
getName: function () {
var that = this
return function () {
return that.name
}
}
}
console.log(obj.getName()())
複製代碼
將this賦值給一個變量,內部函數是能夠訪問外部函數變量的,這樣就解決了spa
閉包是一個容易混淆不清的概念,這篇文章對閉包的定義、執行、常見問題作了簡單的介紹,但願經過這篇能對你們理解和使用閉包有所幫助。若是有錯誤或不嚴謹的地方,歡迎批評指正,若是喜歡,歡迎點贊。code