Javascript閉包與做用域

1.Javascript的做用域是函數做用域而非塊級做用域閉包

//C語言
#include 
void main()
{
   int i=2;
   i--;
   if(i)
   {
       int j=3;
   }
   printf("%d/n",j);      //use an undefined variable:j
}

 

這是由於c中的做用域是塊級的,j是在if後的{ }中定義的,因此沒法訪問,然而在js中會是什麼狀況?函數

    (function(){
        var i=1;
        if(i==1){
            var j=3;
        }
        console.log(j);     //3
    })()

 

在這裏,j是能夠訪問的,也就是說在一個函數中的任何位置定義的變量在該函數中的任何地方都是可見的code

這裏說起一句Javascript的做用域鏈(scope chain),每一個函數定義時都會將他的做用域鏈定設爲他定義的環境ip

function a(){
    function b(){
        //code
    }
}

 

這段代碼中,b的環境爲a,a的環境爲全局(window),在b中查找變量時會先搜索自身函數內部,若是不存在就去a的內部查找,還不存在就去全局中查找,若仍是找不到就是undefined,這就構成一條鏈ci

2.Javascript中變量的做用域分爲全局變量和局部變量作用域

在函數內部能夠訪問全局變量和函數內的局部變量,而在函數外部訪問不到函數內的變量,看代碼rem

var p=11;
function f1(){
   console.log(p);
}
f1();   //11

 

function f1(){
    var p=11;
}
f1();
console.log(p);  //ReferenceError: p is not defined

 

經過這倆段代碼能夠理解全局變量和局部變量,可是定義局部變量時必定要注意加上var,若是不加上其實定義的是一個全局變量,看代碼get

function f1(){
    p=11;
}
f1();
console.log(p);       //11

 

3.那如何訪問函數內部的變量並對它進行操做呢?這裏就須要用到閉包博客

先看看閉包的官方解釋:閉包是一個擁有許多變量和綁定了這些變量的環境的表達式(一般是一個函數),於是這些變量也是該表達式的一部分io

看到這句戶我不由想問,這是個啥?

後來參考了一些博客和《Javascript祕密花園》纔開始理解,閉包大概就是函數內部的一個函數被外部調用,這樣就能夠調用內部變量了,好比下面這段

function f1(){
    var p=11;
        return {
            increment: function() {
                p++;
            },
    
            show: function() {
                alert(p)
            }
        }
}
var f=f1();
f.show();      //11
f.increment();
f.show();      //12

 

先看一下控制檯,f是什麼樣的

這裏能夠看到,f包含increment和show兩個函數,而這兩個函數是f1的內部函數因此能夠訪問p這個變量,在我理解,這裏的increment和show就是f1()的兩個閉包,用他們就能夠從外部調用這個變量

4.閉包能夠作些什麼?

首先我以爲能夠模擬private,就像上面那段代碼,這個變量只能在這個函數內部訪問,也只有使用了閉包才能訪問

第二,和Javascript的垃圾回收有關,這裏我還不是很清楚,等到搞明白了再來補上

5.這裏有一個要注意的就是循環中使用閉包的問題,這裏借用《Javascript祕密花園》裏的一個例子

function f1(){
  for(var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);  
    }, 1000);
  }
}
f1();

 

這段代碼輸出的是10個10而不是指望的0到9,由於閉包內是對i的引用,而後函數執行時i已經變成了10,這裏可使用自執行的匿名函數

function f1(){
  for(var i = 0; i < 10; i++) {
     (function(e) {
        setTimeout(function() {
            console.log(e);  
        }, 1000);
    })(i);

  }
}
f1();

 

這裏的匿名函數將i做爲參數,這裏的e會有i的一個拷貝,而引用時是對e的引用,這就避免了上述的問題

相關文章
相關標籤/搜索