函數執行造成一個私有做用域,保護裏面的私有變量不受外界的干擾,這種保護機制叫作閉包。閉包
一個簡單的閉包:函數
var utils = (function(){
return {
}
})()
複製代碼
在團隊開發過程當中,咱們一般會把本身的代碼存放在一個私有做用域中,若是別人須要使用某些方法的話,能夠經過return或者window.xxx暴露在全局下。this
jQuery源碼也是利用這種保護機制的spa
~function(){
var jQuery = function(){
}
window.$=window.jQuery=jQuery
}()
複製代碼
閉包解決選項卡問題3d
<div class="tabBox" id="tabBox">
<ul>
<li>標題1</li>
<li>標題2</li>
<li>標題3</li>
</ul>
<div class="selected">content1</div>
<div>content2</div>
<div>content3</div>
</div>
var tabBox = document.getElementById('tabBox'),
oList = tabBox.getElementsByTagName('li'),
oDivList = tabBox.getElementsByTagName('div');
function changeTab(index){
//index 存儲當前點擊li的索引
for(var i=0;i<oList.length;i++){
oList[i].className = oDivList[i].className = null //清除樣式
}
oList[i].className = oDivList[i].className = 'selected'
}
for(var i=0;i<oList.length;i++){
oList[i].onclick = function(){
//三次循環給三個li都綁定了一個方法,可是都沒有執行,當循環結束了,i此時爲3,
//等到點擊的時候,就沒法實現想要的效果了
changeTab(index)
}
}
複製代碼
解決辦法是:code
自定義屬性方式(能夠給當前元素加一個屬性)cdn
for(var i=0;i<oList.length;i++){
oList[i].myIndex = i;
oList[i].onclick = function(){
changeTab(this.myIndex)
}
}
複製代碼
閉包機制blog
for(var i=0;i<oList.length;i++){
oList[i].onclick = (function(i){
//執行自執行函數首先會造成一個私有做用域
//接下來 形參賦值 i=0,i=1,i=2
return function(){
changeTab(i)
}
})(i)
}
//造成不銷燬的私有做用域,不必定要有return,咱們也能夠寫成這樣
for(var i=0;i<oList.length;i++){
(function(i){
oList[i].onclick = function(){
//oList[i].onclick佔用了返回的function,因此這個做用域也不會被銷燬
changeTab(i)
}
})(i)
}
複製代碼
如今有這樣一道題索引
function fn(){
var i=1;
return function(n){
console.log(n + i++)
}
}
var f= fn()
f(10) // 11
fn()(10) //11
f(20) //22
fn()(20) //21
複製代碼
首先咱們考慮變量提高內存
function fn(){ //fn內部會造成一個私有做用域,在私有做用域內,會發生形參賦值和變量提高,在這裏並無形參傳遞,咱們只考慮變量提高
var i=1;
return function(n){ //return 引用類型的值纔會讓私有做用域不銷燬
console.log(n + i++) // 先把i=1賦值給結果,而後i本身再加1
}
}
var f;
f= fn() //把fn執行的返回結果賦值給f 實際上f是function(n){console.log(n + i++)}
f(10) //把fn執行的返回結果再執行,而且給它傳遞一個參數10
fn()(10)
f(20)
fn()(20)
複製代碼
函數執行返回了一個
引用數據類型堆內存的地址(而且堆內存隸屬於這個做用域),在外面有一個變量接收了這個返回值,此時當前做用域就不能銷燬(想要銷燬,只須要讓外面的變量賦值爲null)
var num = 1,
obj = {
num:2,
fn:(function(num){
this.num*=2;
num+=2;
return function(){
this.num*=3;
num++;
console.log(num)
}
})(num)
}
var fn = obj.fn;
fn();
obj.fn();
console.log(num,obj.num)
複製代碼