閉包

閉包的概念

函數執行造成一個私有做用域,保護裏面的私有變量不受外界的干擾,這種保護機制叫作閉包。閉包

一個簡單的閉包:函數

var utils = (function(){
    return {
        
    }
})()
複製代碼

閉包的做用

  • 保護(保護私有做用域不受外界干擾)
  • 保存(造成一個不銷燬的私有做用域)

何時用到閉包

  1. 在團隊開發過程當中,咱們一般會把本身的代碼存放在一個私有做用域中,若是別人須要使用某些方法的話,能夠經過return或者window.xxx暴露在全局下。this

  2. jQuery源碼也是利用這種保護機制的spa

    ~function(){
         var jQuery = function(){
             
         }
         window.$=window.jQuery=jQuery
     }()
    複製代碼
  3. 閉包解決選項卡問題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

  1. 自定義屬性方式(能夠給當前元素加一個屬性)cdn

    for(var i=0;i<oList.length;i++){
         oList[i].myIndex = i;
         oList[i].onclick = function(){
             changeTab(this.myIndex)
         }
     }
    複製代碼
  2. 閉包機制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)

閉包與this問題

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)
複製代碼

相關文章
相關標籤/搜索