5.Javascript閉包得實現原理和做用

閉包的實現原理和做用

一、閉包的概念:指有權訪問另外一個函數做用域中的變量的函數,通常狀況就是在一個函數中包含另外一個函數。編程

二、閉包的做用:訪問函數內部變量、保持函數在環境中一直存在,不會被垃圾回收機制處理閉包

      由於函數內部聲明 的變量是局部的,只能在函數內部訪問到,可是函數外部的變量是對函數內部可見的,這就是做用域鏈的特色了。dom

 子級能夠向父級查找變量,逐級查找,找到爲止函數

 1 function  bar(){
 2         //外層函數聲明的變量
 3         var value=1;
 4 
 5         function foo(){
 6             console.log(value);
 7         }
 8         return foo();
 9     };
10     var bar2=bar;
11     //實際上bar()函數並無由於執行完就被垃圾回收機制處理掉
12     //這就是閉包的做用,調用bar()函數,就會執行裏面的foo函數,foo這時就會訪問到外層的變量
13     bar2();

 

所以咱們能夠在函數內部再建立一個函數,這樣對內部的函數來講,外層函數的變量都是可見的,而後咱們就能夠訪問到他的變量了。spa

三、閉包的優勢:code

  • 方便調用上下文中聲明的局部變量
  • 邏輯緊密,能夠在一個函數中再建立個函數,避免了傳參的問題

四、閉包的缺點:對象

      由於使用閉包,能夠使函數在執行完後不被銷燬,保留在內存中,若是大量使用閉包就會形成內存泄露,內存消耗很大blog

 

實際開發中JS閉包的應用

1。在函數外使用函數內的變量 .函數做爲返回值   (閉包做用:避免變量被環境污染)ip

1 function F1(){
2   var a = 100;
3     return function(){
4       console.log(a)    
5     }
6 }
7 var f1 =F1();
8 var a = 200;
9 f1()//100

1 function init(){
2     var name = "hello world";//name是一個被init建立的局部變量
3     function sayName(){//sayName是一個內部函數,閉包
4         alert(name);//使用了父級函數聲明的變量name
5     }
6     sayName();
7 }
8 init();//"hello world"

 

2.函數做爲參數傳遞內存

 1 function F1(){
 2    var a = 100;
 3     return function(){
 4       console.log(a)    
 5     }
 6 }
 7 var f1 =F1();
 8 function F2(fn){
 9   var a = 200;
10      fn();
11 }
12 F2(f1);  // 100

 

3.將函數與其所操做的某些數據關聯起來,一般,你使用只有一個方法的對象的地方,均可以使用閉包

1 // 改變dom樣式
2 document.getElementById("a").onclick = setSize(12);
3     document.getElementById("b").onclick = setSize(18);
4     document.getElementById("c").onclick = setSize(22);
5     function setSize(fontSize){
6         return function(){
7             document.body.style.fontSize = fontSize + 'px';
8         }
9     }

 

4.用閉包模擬私有方法

 1 //這三個公共函數是共享同一個環境的閉包。多虧 JavaScript 的詞法做用域,它們均可以訪問 privateCounter 變量和 changeBy 函數。
 2 var makeCounter = function () {
 3         var privateCounter = 0;
 4         function changeBy(val){
 5             privateCounter += val;
 6         };
 7         return {
 8             increment: function(){
 9                 changeBy(1);
10             },
11             decrement: function(){
12                 changeBy(-1);
13             },
14             value: function(){
15                 return privateCounter;
16             }
17         }
18     };
19     var Counter1 = makeCounter();
20     var Counter2 = makeCounter();
21     Counter1.increment();
22     console.log(Counter1.value());//1 每次調用其中一個計數器時,經過改變這個變量的值,會改變這個閉包的詞法環境。然而在一個閉包內對變量的修改,不會影響到另一個閉包中的變量。
23     console.log(Counter2.value());//0 以這種方式使用閉包,提供了許多與面向對象編程相關的好處 —— 特別是數據隱藏和封裝。

 

5.循環裏面的閉包

怎麼才能實現輸出0-5呢?

1 for (var i = 0; i < 5; i++) {
2   setTimeout(function () {
3     console.log(i);
4   }, 1000 * i);
5 }//55555
//方法一,makeCallback函數爲每個回調建立一個新的詞法環境。
function makeCallback(i) {
     return function() {
        console.log(i)
      };
    }
    for(var i=0;i<10;i++){
        setTimeout(makeCallback(i),1000)
    }
//另外一種方法使用了匿名閉包
for(var i=0;i<10;i++){
        (function(i){
            setTimeout(function () {
                console.log(i)
            },1000)
        })(i)
    }
1 //使用let聲明變量
2 for (let i = 0; i < 5; i++) {
3   setTimeout(function () {
4     console.log(i);
5   }, 1000 * i);
6 }
相關文章
相關標籤/搜索