閉包:從一函數(shù)外部訪問這一函數(shù)的內(nèi)部函數(shù),從而使這一函數(shù)內(nèi)部變量持續(xù)存在的實現(xiàn)
閉包的特性:
函數(shù)嵌套函數(shù)
內(nèi)部函數(shù)引起外部函數(shù)中變量的變化
參數(shù)和變量不會被垃圾回收機(jī)制回收
首先,先來觀察一個簡單的閉包
? ? function fn(){
? ? ? ? var a = 1;
? ? ? ? return function(){? //核心代碼1
? ? ? ? ? ? a++;
? ? ? ? ? ? console.log(a);
? ? ? ? }
? ? }
? ? var carry = fn();? //核心代碼2
? ? carry();? //2
? ? carry();? //3
1
2
3
4
5
6
7
8
9
10
核心代碼1:
fn 函數(shù)執(zhí)行完畢后把一個匿名函數(shù)當(dāng)作返回值返回出來。
核心代碼2:
var carry = fn(); 此行代碼將 fn() 傳遞給變量 carry . 無論是在 Java 還是JavaScript中把一個帶有返回值的方法傳遞給一個變量,那么傳遞的實質(zhì)便是此變量等同于方法的返回值,即 carry 等于返回的匿名函數(shù)
carry = function(){ a++; console.log(a); }
既然 carry 等同于匿名函數(shù),那么對于 carry 來說變量 a 即相當(dāng)于一個全局變量,為了方便理解可以這樣考慮:
在這里插入圖片描述
對于 js 來說函數(shù)是可以隨意嵌套的,那么全局變量也只是相對而言,就像上圖中對于內(nèi)涵函數(shù) carry 來說 a 變量就是一個全局變量,如果只執(zhí)行 carry 那么 a 就不會被重新定義,而是同全局變量一樣保存在內(nèi)存里。這樣就可以實現(xiàn)閉包。
閉包的其他實現(xiàn)方式
IIFE:Immediately Invoked Function Expression,意為立即調(diào)用函數(shù)表達(dá)式。
簡介:如果有些函數(shù)只使用一次,那么立即執(zhí)行就可以,連函數(shù)名都省掉,就是匿名函數(shù)
? ? <script>
? ? (function(){
? ? ? ? console.log("我是匿名函數(shù)");
? ? })();
? ? </script>
1
2
3
4
5
此方法不用被調(diào)用,立即執(zhí)行,并且只執(zhí)行一次。
在最開始的例子中我們發(fā)現(xiàn)外部函數(shù) fn 的變量定義只定義一次,閉包的核心只在返回函數(shù),那么為了節(jié)省全局變量可以將外部函數(shù)設(shè)為 IIFE 。
閉包實現(xiàn)中最重要的便是講內(nèi)部函數(shù)暴露在外面,下面講解一下用 IIFE 實現(xiàn),和暴露內(nèi)部函數(shù)的方法
暴露內(nèi)部函數(shù)的方法一:通過return返回內(nèi)部函數(shù)
? ? var fn = (function(){
? ? ? ? var a = 1;
? ? ? ? function add(){
? ? ? ? ? ? a++;
? ? ? ? }
? ? ? ? function print(){
? ? ? ? ? ? console.log(a);
? ? ? ? }
? ? ? ? return {add,print}
? ? })();
? ? var add = fn.add;
? ? var print = fn.print;
? ? add();
? ? print();? //2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
暴露內(nèi)部函數(shù)的方法一:通過全局對象 window 將內(nèi)部函數(shù)暴露出來
? (function(){
? ? ? var a = 1;
? ? ? function add(){
? ? ? ? ? a++;
? ? ? }
? ? ? function print(){
? ? ? ? ? console.log(a);
? ? ? }
? ? ? window.fn={add,print}
? })();
? var add = fn.add;
? var print = fn.print;
? add();
? print();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
文章最后發(fā)布于: 2019-11-16