讓我們一起來學習一下什麼是javascript的閉包

什麼是閉包:
閉包是一個存在內部函數的引用關系。
該引用指向的是外部函數的局部變量對象(前提是內部函數使用瞭外部函數的局部變量)
閉包的作用:
延長外部函數變量對象的生命周期
使用閉包能夠間接的從函數外部訪問函數內部的私有變量

一、常見的閉包

function outer() {
  var a = 1
  function inner() {
    console.log(a)    //1
  }
  inner()
}
outer()

二、實例詳解

function createFunc() {
  var result = new Array()
  for (var i = 0; i < 10; i++) {
    result[i] = function () {
      console.log(i)
    }
  }
  return result
}
var result = createFunc()
result[0]() //10
result[1]() //10
result[2]() //10
result[3]() //10
result[4]() //10
result[5]() //10
result[6]() //10
result[7]() //10

首先在代碼執行前,會先創建一個全局的對象,其中包含著全局的屬性,並且將其放入全局上下文作用域鏈頂端,並且也將其放入每一個函數的作用域鏈頂端。以這個例子為例。如圖所示 

在這裡插入圖片描述

在初始化結束後,開始執行代碼,此時就會創建一個新的對象,叫做Active Object,其中放入一些參數,並且將其壓入createFunc函數的作用域鏈中。 

在這裡插入圖片描述

因為在createFunc中仍然定義函數result[i]..,所以在執行代碼前,該函數會形成作用域鏈。 

在這裡插入圖片描述

此時開始執行createFunc函數,當指向完畢後,createFunc中的作用域鏈表現為。如下圖所示。此時result為一個數組。並且Active object已經從createFunc作用域鏈的頂部刪除。 

在這裡插入圖片描述

此時開始執行result[0](這裡以result[0]為例,其他的一樣),此時執行result[0]之前,應該創建一個新的Active object對象,將其放入result[0]執行作用域棧中。如圖所示

在這裡插入圖片描述

此時函數執行中需要訪問i,但是在active object並不存在i,所以此時需要沿著作用域鏈進行查找,在createFunc中找到i,並且i的值為10,所以最終打印的值都是10。在createFunc執行完畢後,其創建的對象並沒有被垃圾回收掉,因為在result[0]中的i依然保持對該對象的引用。 

這個例子的解決方法如下所示,就是設置一個立即執行函數,每一個下標對應的函數,都是立即執行函數,當立即執行函數執行時,每一個函數的上下文對象中都會存在為正確的下標值。

function createFunc() {
  var result = new Array()
  for (var i = 0; i < 10; i++) {
    result[i] = (function (num) {
      return function() {
        console.log(num)
      }
    })(i)
  }
  return result
}
var result = createFunc()
result[0]() //0
result[1]() //1
result[2]() //2
result[3]() //3
result[4]() //4
result[5]() //5
result[6]() //6
result[7]() //7

總結

本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容! 

推薦閱讀: