做用域、做用域鏈、閉包

做用域、做用域鏈

1、Js之前沒有塊級做用域,不過在ES6中有let了。html

2、Js使用函數做用域閉包

function aaa(){
        var a = "a";
    }
    console.log(a);//報錯

3、聲明提早函數

console.log(aaa)//報錯
console.log(aaa);//undefined 聲明未定義
var aaa;
console.log(aaa); //undefined 聲明未定義
var aaa = "aaa";

4、Js的做用域鏈spa

複製代碼
function Fun(){
    var aaa = "aaa",
         fun = "fun";
    function Inter(){
        var aaa = "ccc";
        console.log(aaa); //ccc
        console.log(fun); //fun
    }
    Inter();
}
Fun();
複製代碼

Inter的做用域鏈翻譯

找到就中止查找返回數據,找不到就延做用域鏈查找,直到Global也查不到就返回報錯;debug

5、Js的做用域鏈在執行前已經被建立rest

 閉包

1、閉包:是指有權訪問另外一個函數做用域中的變量的函數;code

2、閉包的特色:局部變量不會被垃圾回收;htm

 

//定義一個函數時,實際是保存它的做用域鏈。當調用這個函數時,會建立一個新的對象來保存局部變量,而且把這個新的對象添加到做用域鏈上。當函數返回時,將做用域鏈中的這個對象刪除。對象

//若是這個函數定義了嵌套函數,並將它做爲返回值返回或者存儲在某處的屬性裏,就會有一個外部的引用指向這個嵌套函數。

3、上面那句是書上的話,很差理解。我翻譯下就是父函數內建立的變量,子函數調用。只要子函數沒有被銷燬,父函數和建立的變量就不會被銷燬。

舉個栗子

複製代碼
function counter(){
        var a = 0;
        function rest(){
            console.log(a++);
        }
        return rest;
    }
    var scope = counter();
    scope();//0
    scope();//1
    scope();//2
複製代碼

建立閉包的常見方式,就是在一個函數內部建立另外一個函數,外部函數將內部函數做爲返回值返回。有的時候這個外部是全局。

for(var i = 0;i<elements.length;i++){
        elements[i].onclick = function(){
            console.log(i);  //elements.length
        }
    }

上面每次點擊,輸出的都是elements.length。由於onclick是一個點擊的函數,不能被銷燬,因此i也不能被銷燬保存在Global中。因此點擊輸出的是elements.length。

複製代碼
for(var i = 0;i<elements.length;i++){
        function F(n){
            elements[n].onclick = function(){
                console.log(n);
            }
        }
        F(i);
    }
複製代碼

這樣修改下就能夠了。

4、垃圾回收機制:若是一個對象再也不被引用,這個對象會被GC回收。若是兩個對象相互引用,這兩個都會被回收。若是a被b引用,b又被c引用,就不會被回收,就是閉包第一個例子的緣由。

5、閉包的兩種寫法

複製代碼
function counter(){
        var a = 0;
        function rest(){debugger
            return a;
        }
        return rest();
    }
    counter();
複製代碼

定義調用在同一做用域

複製代碼
    function counter(){
        var a = 0;
        function rest(){debugger
            return a;
        }
        return rest;
    }
    //counter()();
    var scopt = counter();
    scopt();
複製代碼

定義調用不在同一做用域

原文:http://www.cnblogs.com/taohuashan/p/6689619.html

相關文章
相關標籤/搜索