01
JS中變量的作用域
在理解閉包之前,我們得弄清楚JS中變量的作用域原理,它分為全局作用域和局部作用域,它有一個特點就是局部可以獲取全局的聲明變量,而全局卻不能得到局部聲明的變量,我們先來看一個小例子:
1 var num = 99;
2 function foo(){
3 var hit = 88;
4 console.log(num);
5 }
6 foo(); //99
7 console.log(hit); //報錯,找不到hit變量
當然在局部聲明變量的時候一定要用var或者let,不然會在全局生成一個變量,容易照成全局汙染,上面代碼如果hit沒有var聲明:
1 var num = 99;
2 function foo(){
3 hit = 88;
4 console.log(num);
5 }
6 foo(); //99
7 console.log(hit); //88
需要web前端資料要的話轉發私信小編“web前端”
02
什麼是閉包
那麼現在問題來了,如果我們非要從外部來讀取局部變量中的聲明變量呢,尋常方式不行,我們可以變通一下,就是在函數內部再嵌套一個函數,然後返回這個嵌套函數:
1 function foo(){
2 var hit = 88;
3 return function num(){
4 console.log(hit)
5 }
6 }
7 var num1 = foo();
8 num1(); //88
這樣,控制檯就會打印出hit變量的值了,其實在上面的代碼中,被返回的函數num()就產生了閉包,由於在js中,只有函數內部的子函數才能讀取局部變量,所以可以把閉包理解成定義在一個函數內部的函數,簡單的說,JavaScript允許使用內部函數:即函數定義和函數表達式位於另一個函數的函數體內而且,這些內部函數可以訪問它們所在的外部函數中聲明的所有局部變量、參數和聲明的其他內部函數。當其中一個這樣的內部函數在包含它們的外部函數之外被調用時,就會形成閉包。
03
閉包的用途
- 相信大家對閉包的概念已經有了簡單的認識,我們接著探討閉包的表達形式以及用途。
(1)匿名自執行函數
1 (function(){
2 var foo = function(){
3 console.log('執行完函數後銷燬')
4 };
5 foo();
6 })();
上面代碼也是閉包的應用,運用於函數只會執行一次的場景,執行完便會被釋放。
(2)給對象設置私有變量
1 var result = function(){
2 var count = 1;
3
4 return function (){
5 count++;
6 console.log(count)
7 }
8 }()
9
10 result(); //2
11 result(); //3
12 result(); //4
13 result(); //5
上面代碼可以保存自己的私有變量,防止代碼之間的衝突。
(3)異步執行函數
下面先看一個小例子:
1 for(var i=0;i<5;i++){
2 console.log(i); //0,1,2,3,4
3 }
4 for(var i=0;i<5;i++){
5 setTimeout(()=>{
6 console.log(i); //5,5,5,5,5
7 },0)
8 }
為什麼會出現上述差異呢,原因在於setTimeout是異步加載,所以為先循環結束後輸出最後結果,如果我們就是想實現輸出0,1,2,3,4呢。那就要用到閉包了:
1 for(var i=0;i<5;i++){
2
3 (function(i){
4 setTimeout(()=>{
5 console.log(i); //0,1,2,3,4
6 },0);
7 })(i);
8 }
上面就是異步調用閉包,它可以讓變量值始終保存在內存中,即使外部的執行環境已經結束了。
需要web前端資料要的話轉發私信小編“web前端”
04
閉包的優缺點
(1)由於閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存洩露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。
(2)閉包會在父函數外部,改變父函數內部變量的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變量的值。
需要web前端資料要的話轉發私信小編“web前端”
閱讀更多 芒果教你學編程 的文章
關鍵字: 局部 作用域 JavaScript