閉包
閉包
任何的書,講閉包,一定是下面的經典案例:
1 function outer(){ 2 var a = 333; 3 function inner(){ 4 console.log(a); 5 } 6 return inner; 7 } 8 9 var inn = outer(); 10 inn(); //彈出333 |
推導過程:
我們之前已經學習過,inner()這個函數不能在outer外面調用,因為outer外面沒有inner的定義:
1 function outer(){ 2 var a = 888; 3 function inner(){ 4 console.log(a); 5 } 6 } 7 //在全局調用inner但是全局沒有inner的定義,所以報錯 8 inner(); |
但是我們現在就想在全局作用域下,運行outer內部的inner,此時我們必須想一些奇奇怪怪的方法。
有一個簡單可行的辦法,就是讓outer自己return掉inner:
1 function outer(){ 2 var a = 333; 3 function inner(){ 4 console.log(a); 5 } 6 return inner; //outer返回了inner的引用 7 } 8 9 var inn = outer(); //inn就是inner函數了 10 inn(); //執行inn,全局作用域下沒有a的定義 11 //但是函數閉包,能夠把定義函數的時候的作用域一起記憶住 12 //能夠輸出333 |
這就說明了,inner函數能夠持久保存自己定義時的所處環境,並且即使自己在其他的環境被調用的時候,依然可以訪問自己定義時所處環境的值。
一個函數可以把它自己內部的語句,和自己聲明時所處的作用域一起封裝成了一個密閉環境,我們稱為“閉包” (Closures)。
每個函數都是閉包,每個函數天生都能夠記憶自己定義時所處的作用域環境。但是,我們必須將這個函數,挪到別的作用域,才能更好的觀察閉包。這樣才能實驗它有沒有把作用域給“記住”。
我們發現,把一個函數從它定義的那個作用域,挪走,運行。嘿,這個函數居然能夠記憶住定義時的那個作用域。不管函數走到哪里,定義時的作用域就帶到了哪里。這就是閉包。
閉包在工作中是一個用來防止產生隱患的事情,而不是加以利用的性質。
因為我們總喜歡在函數定義的環境中運行函數。從來不會把函數往外挪。那為啥學習閉包,防止一些隱患,面試絕對考。
閉包的性質
每次重新引用函數的時候,閉包是全新的。
1 function outer(){ 2 var count = 0; 3 function inner(){ 4 count++; 5 console.log(count); 6 } 7 return inner; 8 } 9 10 var inn1 = outer(); 11 var inn2 = outer(); 12 13 inn1(); //1 14 inn1(); //2 15 inn1(); //3 16 inn1(); //4 17 inn2(); //1 18 inn2(); //2 19 inn1(); //5 |
無論它在何處被調用,它總是能訪問它定義時所處作用域中的全部變量