閉包這個概念做爲前端來講算是耳熟能詳了,基本是面試的時候必問的問題,基本上隨便找個前端都能說出點什麼。 閉包指的是:可以訪問另外一個函數做用域的變量的函數。清晰的講:閉包就是一個函數,這個函數可以訪問其餘函數的做用域中的變量 例以下面這個例子eg1:前端
function A() {
var b = 1
function C() {
console.log(b) // 函數C就是一個閉包
return b++
}
return C
}
複製代碼
一般咱們面試的時候都會給這麼一個例子。 以前面試的人還給咱們寫出了這麼一個例子eg2:es6
var b = 1
function A() {
console.log(b)
return b++
}
複製代碼
我當時直接就否認了他,說這不是。直到今晚我又一次讀高程的時候,裏面也寫到了這麼一個例子,我頓時感到一陣後怕,立刻又看了一下閉包的概念。書中說到:該函數能使用函數外定義的變量,那麼咱們來看上面的那個例子不正是這樣子的嗎?頓時一頓汗顏。那麼咱們來講說閉包的使用場景和優缺點吧。面試
1.從外部訪問函數的變量閉包
經過上eg1能夠看出咱們執行A()的時候會給咱們返回函數C而且攜帶了變量b,這能爲咱們作什麼事情呢?看下面一個例子eg3:
複製代碼
function create_counter(initial) {
var x = initial || 0
return {
function inc() {
x += 1
return x
}
}
}
var c1 = create_counter()
c1.inc() // 1
c1.inc() // 2
c1.inc() // 3
var c2 = create_counter(10)
c2.inc() // 11
複製代碼
2.模擬塊級做用域 eg4:函數
function count() {
var arr = []
for (var i=1; i<=3; i++) {
arr.push(function () {
return i * i
});
}
return arr
}
var c1 = count()
var f1 = c1[0]
var f2 = c1[1]
var f3 = c1[2]
複製代碼
看上面的代碼咱們也許會想到返回的arr是三個函數分別是ui
c1 = [function() {return 11}, function() {return 22}, function() {return 3*3}] 依次調用f1,f2,f3會獲得1,4,9,可是結果都是16 緣由就在於返回的函數引用了變量i,但它並不是馬上執行。等到3個函數都返回時,它們所引用的變量i已經變成了4,所以最終結果爲16。 那麼按照閉包的定義咱們對以上代碼作修改 eg5:this
function count() {
var arr = []
for (var i=1; i<=3; i++) {
arr.push((function (n) {
return n * n
})(i));
}
return arr
}
var c1 = count()
var f1 = c1[0]
var f2 = c1[1]
var f3 = c1[2]
複製代碼
這裏使用了匿名函數的自調用,在函數內部使用就是一個閉包,由於它能反問外部函數的任何變量。如今再執行就會獲得1,4,9 固然有了es6的let後已經不須要這麼麻煩了。spa
1.this的指向問題code
eg6:內存
var INFO = {
name: '哈哈哈',
sayName: function () {
return function () {
console.log(this.name)
}
}
}
複製代碼
由於這裏的執行環境是window了因此這裏的this指向不是INFO了。
2.內存泄露問題 eg7:
function test() {
var a = 1
function innerFunc () {
console.log(a)
}
return innerFunc
}
var f1 = test()
f1() // 1
複製代碼
按照js的回收機制是執行完就回收,那麼執行完test 變量就應該被回收了,可是沒有,由於返回的innerFunc中使用了變量a,因此test不能被回收,如何避免呢,那就是執行完之後手動清除。
菜雞一個,有錯誤請指出。