[重學前端基礎] 深刻理解Javascript中的閉包

前言

本文將從如下幾個點來展開:git

什麼是閉包?

怎麼建立閉包?github

閉包的應用閉包

什麼是閉包?

函數執行完,其內部函數還保持着對它的做用域的引用,這個引用就是閉包。ide

內部函數對包含它的函數做用域保持着引用意味着什麼?函數

也就是函數執行完,內存被釋放,可是其做用域還存在內部函數的執行上下文中,還能在內部函數中訪問到函數做用域中的變量。ui

怎麼建立閉包?

也就是如何讓內部函數對包含它的函數的做用域始終保持引用呢?code

沒有建立閉包的例子:對象

function addValue() {
     var value = 1
     return function add () {
         return value++
     }
 }
 
console.log( addValue()() ) //1
console.log( addValue()() ) //1

example1的栗子不能算閉包,由於內部函數並無對包含它的函數做用域保持引用。每次調用addValue方法,value都是1。若是像example2同樣將addValue返回的函數賦值給一個全局變量,那麼在程序卸載以前,內部函數一直被全局變量引用着,因此addValue內存始終不會被釋放。以下:ip

建立了閉包的例子:內存

function addValue() {
     var value = 1
     return function add () {
         return value++
     }
 }
 
 var b = addValue()
console.log( b() ) //1
console.log( b() ) //2

函數做用域是在執行時建立的,當函數執行完,內存就會被釋放,函數內部變量不能在函數外部被訪問。可是若是函數一直被引用着,那麼函數內存就不會被釋放,函數中的變量就不會被銷燬,包含該函數做用域的函數就能訪問到該函數中的變量。

對於一個函數而言,函數中的變量只能在被激活的時候才能訪問到,也就是在函數內部才能訪問到,當函數執行完內存就會被釋放,也就是函數執行上下文就會被銷燬,對應的執行上下文中的活動對象保存的變量也會被銷燬。

基於js的垃圾(內存)回收機制,若是函數一直被引用着函數一直處於激活(被使用的)狀態,其內存就一直不會被回收,其執行上下文一直存在,保存的變量對象也一直存在。

閉包的應用

一、建立私有模塊

var module = (function() {
  var person = {
    name: "phillip",
    age: 29,
    location: "Utah"
  };

  function privateMethod(){
    return "Hi, I'm " + person.name + ", age " + person.age + " from " + person.location;
  }

  // Anything that is being returned is made public and can be invoked from
  // outside our lexical scope
  return {
    // Code here.
    privateMethod: privateMethod
  };

})();

module.privateMethod()

二、保留記錄

var friends = ["Tom", "Dick", "Harry"];
var secondLevelFriends = ["Anne", "Harry", "Quinton"];
var allUsers = ["Tom", "Dick", "Harry", "Anne", "Quinton", "Katie", "Mary"];

function findPotentialFriends(existingFriends) {
   return function (friend) {
       return existingFriends.indexOf(friend) > -1 ? false : true
   }
}

var isNotAFriend = findPotentialFriends( friends );
// isNotAFriend(allUsers[0]); // false
// isNotAFriend(secondLevelFriends[2]); // true

最後

檢驗閉包掌握狀況:

function fo() {
    var i = 0;
    return function (n) {
        return n+i++ //++ 先賦值再+1
    }
    
}

var f = fo()
console.log(f(15)) //15
console.log(fo()(15)) //15
console.log(fo()(20)) //20
console.log(f(20)) //21

要了解閉包保存函數內部變量的原理,必須瞭解了函數執行上下文、變量對象、做用域鏈、函數做用域、垃圾回收內存釋放的知識,能夠參考下面的文章:

那麼Js中究竟是如何管理變量(何時會被回收內存)的呢?
http://note.youdao.com/notesh...
函數做用域(函數中如何訪問變量呢)是怎麼一回事呢?
http://note.youdao.com/notesh...

參考資料

JavaScript深刻之閉包

Javascript內存管理

相關文章
相關標籤/搜索