介紹你下你理解的閉包?無論怎樣!我最近聽到不少次!感受是很差好總結一下無法面對那些犀利的追問!
若是以爲閉包理解的很透徹,就直接跳到最後看題目!html
小紅書的解釋閉包是有權訪問另外一個函數做用域中的變量的函數。明白了嗎?就是一個函數,一個能夠訪問其餘函數中變量的函數。因此常見的建立閉包的方式就是在一個函數內部建立另外一個函數。windows
function bag(num){ return function(){ return num } } var bagc = bag(12) console.log(bagc()) //12
能夠看到在bag內部的匿名函數能夠訪問外部bag函數的變量num。數組
閉包能夠用在許多地方。它的最大用處有兩個,一個是能夠讀取函數內部的變量,另外一個就是讓這些變量的值始終保持在內存中。閉包
function f1(){ var n=999; nAdd=function(){n+=1} function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999 nAdd(); //變量n被保存了 result(); // 1000
上面是阮一峯在文檔中的一個例子,讀取函數內部變量我以爲用處通常吧,讓變量保持在內存中的用處卻是很多,像常用的that=this等。下面看一個常見的問題:app
for(var i = 0;i <10;i++){ setTimeout(()=>{ console.log(i) },1000) } //上面的代碼咱們但願按照索引值打印,結果卻打印了10個10,爲何就不解釋了,i是全局變量。 //換成下面的寫法,就能解決問題,正是由於閉包 讓變量的值始終保持在內存中,每一個i都存在了num這個局部變量中 for(var i = 0;i <10;i++){ (function(num){ setTimeout(()=>{ console.log(num) },1000) })(i) }
閉包雖然在解決一些問題上有好處,可是由此引起的一些問題要注意,並且因爲閉包會攜帶外部函數做用域,因此內存佔用比較大,因此儘可能少用、慎用閉包。dom
正是由於閉包可使用外部變量,因此下面的代碼中,返回的匿名函數中對變量i的使用將會是最終的值,數組中存放的函數的返回值將都會是10。函數
function test() { var result = []; for(var i = 0; i<10; i++){ result.[i] = function () { return i; } } return result }
須要將上述代碼改寫成以下:測試
function test() { var result = []; for(var i = 0; i<10; i++){ result.[i] = function (num) { return function() { console.info(num); } }(i) } return result }
此時訪問的num,是上層函數執行環境的num,數組有10個函數對象,每一個對象的執行環境下的number都不同。this
匿名函數的執行具備全局性,因此閉包函數的this通常指向window;code
var object = { name: "object", getName:function() { return function() { console.info(this.name) } } } object.getName()() // underfined // 由於裏面的閉包函數是在window做用域下執行的,也就是說,this指向windows
能夠改寫成以下:
var object = { name: "object", getName:function() { var that = this; return function() { console.info(that.name) } } } object.getName()() // object
若是閉包在做用域鏈中保存着html元素,則該元素內存將沒法自動銷燬。
function showId() { var el = document.getElementById("app") el.onclick = function(){ aler(el.id) // 這樣會致使閉包引用外層的el,當執行完showId後,el沒法釋放 } } // 改爲下面 function showId() { var el = document.getElementById("app") var id = el.id el.onclick = function(){ aler(id) // 這樣會致使閉包引用外層的el,當執行完showId後,el沒法釋放 } el = null // 主動釋放el }
好了,看到這裏是否是感受對閉包理解的很到位了?彆着急,看看這兩個小問題測試一下!
var Test = { close:function(val){ return function (z){ return ++ val +z } } } var getClose = function(val){ return Test[val] } var fn = getClose('close') var cover = fn(100) console.log(cover(200)) console.log(cover(300)) console.log(fn(100)(200)) console.log(fn(100)(200)) console.log(getClose('close')(100)(300)) //輸出結果見結尾處
var container1 = document.getElementById('container1') var container2 = document.getElementById('container2') var container3 = document.getElementById('container3') var container4 = document.getElementById('container4') var container5 = document.getElementById('container5') var innerHTML = 'window的html' var events = { innerHTML:'我是events', getHtml:function (){ console.log(this.innerHTML) }, setFun:function(){ return this.getHtml }, proxy:function(){ var self = this; return function(){ self.getHtml() } } } container1.onclick = events.getHtml; container2.onclick = events.setFun(); container3.onclick = events.proxy(); container4.onclick = function(){ window.setTimeout(events.setFun(),0) } container5.onclick = function(){ window.setTimeout(events.proxy(),0) }
還ok?有沒有被繞暈!暈了就打開電腦敲吧
看一下輸出結果吧 第一題:401 402 301 301 401 第二題:container container2 我是events window的html 我是events