js函數閉包瞭解一下

介紹你下你理解的閉包?無論怎樣!我最近聽到不少次!感受是很差好總結一下無法面對那些犀利的追問!
若是以爲閉包理解的很透徹,就直接跳到最後看題目!html

1.閉包概念

小紅書的解釋閉包是有權訪問另外一個函數做用域中的變量的函數。明白了嗎?就是一個函數,一個能夠訪問其餘函數中變量的函數。因此常見的建立閉包的方式就是在一個函數內部建立另外一個函數。windows

function bag(num){
    return function(){
        return num
    }
}
var bagc = bag(12)
console.log(bagc()) //12

能夠看到在bag內部的匿名函數能夠訪問外部bag函數的變量num。數組

2.閉包的用處

閉包能夠用在許多地方。它的最大用處有兩個,一個是能夠讀取函數內部的變量,另外一個就是讓這些變量的值始終保持在內存中閉包

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)
   }

3.使用閉包須要注意的點

閉包雖然在解決一些問題上有好處,可是由此引起的一些問題要注意,並且因爲閉包會攜帶外部函數做用域,因此內存佔用比較大,因此儘可能少用、慎用閉包。dom

1.變量問題

正是由於閉包可使用外部變量,因此下面的代碼中,返回的匿名函數中對變量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

2.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

3.內存泄漏問題

若是閉包在做用域鏈中保存着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
}

4.閉包練習題

好了,看到這裏是否是感受對閉包理解的很到位了?彆着急,看看這兩個小問題測試一下!

1.與函數調用結合

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))

//輸出結果見結尾處

2.與dom結合

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
相關文章
相關標籤/搜索