JavaScript中閉包的概念、原理、作用及應用
一、閉包概念
閉包:有權訪問另一個函數(shù)作用域中的變量的函數(shù);一般情況就是在一個函數(shù)中包含另一個函數(shù)。
從官方定義我們知道閉包是一個函數(shù),只不過這個函數(shù)有[超能力],可以訪問到另一個函數(shù)的作用域。
為什么說這個叫做[超能力]呢?
因為我們知道函數(shù)作用域是獨立的、封閉的,外部的執(zhí)行環(huán)境是訪問不了的,但是閉包具有這個能力和權限。
那閉包是怎樣的一個表現(xiàn)形式呢?
第一,閉包是一個函數(shù),而且存在于另一個函數(shù)當中
第二,閉包可以訪問到父級函數(shù)的變量,且該變量不會銷毀
- function person(){
- var name = '有魚';
- function cat(){
- console.log(name);
- }
- return cat;
- }
- var per = person();// per的值就是return后的結果,即cat函數(shù)
- per();// 有魚 per()就相當于cat()
- per();// 有魚 同上,而且變量name沒有銷毀,一直存在內存中,供函數(shù)cat調用
- per();// 有魚
二、閉包原理
閉包的實現(xiàn)原理,其實是利用了作用域鏈的特性,我們都知道作用域鏈就是在當前執(zhí)行環(huán)境下訪問某個變量時,如果不存在就一直向外層尋找,最終尋找到最外層也就是全局作用域,這樣就形成了一個鏈條。
例如:
- var age = 18;
- function cat(){
- age++;
- console.log(age);// cat函數(shù)內輸出age,該作用域沒有,則向外層尋找,結果找到了,輸出[19];
- }
- cat();//19
看到這里,大家都會說這不就是最簡單的函數(shù)和變量形式嗎?閉包在哪里?別急,我們接著往下看:
如果我們再次調用時,結果會一直增加,也就變量age的值一直遞增。
- cat();//20
- cat();//21
- cat();//22
如果程序還有其他函數(shù),也需要用到age的值,則會受到影響,而且全局變量還容易被人修改,比較不安全,這就是全局變量容易污染的原因,所以我們必須解決變量污染問題,那就是把變量封裝到函數(shù)內,讓它成為局部變量。
- function person(){
- var age = 18;
- function cat(){
- age++;
- console.log(age);
- }
- return cat;
- }
- person();// 19
- person();// 19
這里又出現(xiàn)問題了,每次調用函數(shù)person,進入該作用域,變量age就會重新賦值為18,所以cat的值一直是19;所以需要做一下調整:
- var per = person();//per相當于函數(shù)cat
- per();// 19 即cat() 這樣每次調用不在經過age的初始值,這樣就可以一直增加了
- per();// 20
- per();// 21
而且變量age在函數(shù)內部,不易修改和外泄,相對來說比較安全。
三、閉包作用
作用1:隱藏變量,避免全局污染
作用2:可以讀取函數(shù)內部的變量
同時閉包使用不當,優(yōu)點就變成了缺點:
缺點1:導致變量不會被垃圾回收機制回收,造成內存消耗
缺點2:不恰當?shù)氖褂瞄]包可能會造成內存泄漏的問題
這里簡單說一下,為什么使用閉包時變量不會被垃圾回收機制收銷毀呢,這里需要了解一下JS垃圾回收機制;
JS規(guī)定在一個函數(shù)作用域內,程序執(zhí)行完以后變量就會被銷毀,這樣可節(jié)省內存;使用閉包時,按照作用域鏈的特點,閉包(函數(shù))外面的變量不會被銷毀,因為函數(shù)會一直被調用,所以一直存在,如果閉包使用過多會造成內存銷毀。
四、閉包應用
需求:實現(xiàn)變量a 自增
1、通過全局變量,可以實現(xiàn),但會污染其他程序
- var a = 10;
- function Add(){
- a++;
- console.log(a);
- }
- Add();
- Add();
- Add();
2、定義一個局部變量,不污染全局,但是實現(xiàn)不了遞增
- var a = 10;
- function Add2(){
- var a = 10;
- a++;
- console.log(a);
- }
- Add2();
- Add2();
- Add2();
- console.log(a);
3、通過閉包,可以是函數(shù)內部局部變量遞增,不會影響全部變量,完美!!
- var a = 10;
- function Add3(){
- var a = 10;
- return function(){
- a++;
- return a;
- };
- };
- var cc = Add3();
- console.log(cc());
- console.log(cc());
- console.log(cc());
- console.log(a);