閉包是指有權訪問另外一個函數做用域中變量的函數,建立閉包的最多見的方式就是在一個函數內建立另外一個函數,經過另外一個函數訪問這個函數的局部變量,利用閉包能夠突破做用鏈域,將函數內部的變量和方法傳遞到外部。 //閉包特性:html
(1)函數內再嵌套函數面試
(2)內部函數能夠引用外層的參數和變量閉包
(3)參數和變量不會被垃圾回收機制回收函數
閉包簡單來說就是函數的嵌套,在開發過程當中,咱們須要保證函數內的 變量能按照咱們的需求保存在內存中可讓外部函數訪問到這個變量,那麼這個地方就會用到閉包。爲了方便理解上面這段話,那麼就要講一下做用域和垃圾回收機制。指針
來個小插曲code
js中的變量類型包括:基礎數據有Number、String、Boolean、Undefined、Null,另外還有一種數據類型就是Object。 內存分爲棧區(stack)和堆區(heap),而後在JS中開發人員並不能直接操做堆區,堆區數據由JS引擎操做完成,針對js中的變量,其存儲方式以下圖: htm
從上圖中能夠知道,對基本數據類型來講,只使用了內存的棧區,對於object數據來講,堆棧都使用了圖片
js中分局部變量和全局變量,以下:內存
var time=10 //全局變量 function a(){ console.log(time) } a(); function b(){ var time=10 //局部變量,外部函數是訪問不到此變量 return time; } console.log(b())
先來個小插曲作用域
要訪問函數的引用(指針)而不是執行函數時,必須去掉圓括號,加上圓括號表示訪問函數執行後的結果 函數體內部的語句在執行時,一旦遇到return,函數就會結束(後面的代碼不會執行),並返回返回值 返回值能夠是任何類型的值,若是沒有return或只有return而沒有返回值,則函數返回默認值undefined
function a(){ var time+=10; console.log(time) //11 //函數沒有返回值 } console.log(a()) //undefined
js中垃圾回收機制 固然這裏只講一部分 主要針對的是局部變量回收,函數內部的變量在函數執行的過程當中存在,在這個過程當中,局部變量在堆棧內存中分配空間以便存儲它們的值,當函數執行完後,這些函數內部的局部變量就會從內存中被釋放,而有時候咱們須要函數內部的局部變量能按照咱們的需求保存在內存中可讓外部函數訪問到這個變量,這就用到了閉包。
###** 閉包主要部分**
閉包的建立 一個函數中嵌套另一個函數,而且將這個函數return出去,而後將這個return出去的函數保存到一個變量中,那麼這樣就建立了閉包
function a(){ var b=10; console.log(++b) } a();//11 a();//11
爲啥a函數執行兩次,輸出的依舊是11,函數每次執行完後,其內的局部變量b就會從內存中釋放。爲了讓函數每執行一次,b就加1,代碼以下:
function a(){ var b=10; function d(){ b++; console.log(b) } return d; } var c=a(); c(); c();
函數a內部的局部變量b沒有被釋放,那是由於a函數被變量c引用了,函數返回的是函數d。 若是某個函數被它的父函數以外的一個變量引用,就造成了一個閉包
另外還有一種常見的閉包寫法:
var a=(function (){ var b=10; function c(){ b++; console.log(b) } return c })()//這個自執行函數執行完後,返回會函數c,其實也就是 //var a=function c(){ // b++; // console.log(b) //} a();//11 a();//12
另外寫一個面試中常常提到的一個閉包題目(開發中常常會用到),上代碼... html代碼以下:
<ul> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul>
不使用閉包:
window.onload = function(){ var ul = document.getElementsByTagName("ul")[0]; var li = ul.getElementsByTagName("li"); for(var i=0;i<li.length;i++){ li[i].onclick = function(){ console.log(i); //無論我怎麼點都是返回6 } } }
使用閉包:
window.onload = function(){ var ul = document.getElementsByTagName("ul")[0]; var li = ul.getElementsByTagName("li"); for(var i=0;i<li.length;i++){ (function(i){ li[i].onclick = function(){ console.log(i); //點擊第幾個返回第幾個 } })(i) } }