首頁  >  文章  >  web前端  >  javascript作用域與閉包使用詳解_基礎知識

javascript作用域與閉包使用詳解_基礎知識

WBOY
WBOY原創
2016-05-16 16:51:11928瀏覽

作用域的巢狀將形成作用域鏈,函數的巢狀將形成閉包。閉包與作用域鍊是 JavaScript 區別於其它語言的重要特性之一。

作用域
JavaScript 中有兩種作用域:函數作用域和全域作用域。

在一個函數中宣告的變數以及該函數的參數享有同一個作用域,即函數作用域。一個簡單的函數作用域的例子:

複製程式碼 程式碼如下:

function foo() {


function foo() {


function foo() {
;
    {        var bar = 2;

    }

    return bar

不同於C等其它有塊作用域的語言,這裡將始終返回 2 。

全域作用域,對瀏覽器來說可以理解為window 物件(Node.js則是global):複製程式碼

複製程式碼


程式碼如下:
var bar = 1;

function foo() {}

alert(window.bar); // 1

alert(window.foo) ; // "function foo() {}"


複製程式碼


程式碼如下:


var scope = 0, zero = "gloscope" ;
(function(){
    var scope = 1, one = "scope-1";
    (function(){
        (function(){
        (function(){
      🎜>        (function(){
            var scope = 3, three = "scope-3" pe
            console.log([three, two, one, zero].join(" "));
            console.log(scope); // 3
        })();
        console.log(typeof three); // undefined
        console.log(scope); // 2
    })();
    console.log(typeof two); // undefined> })();

console.log(typeof one); // undefined

console.log(scope); // 0


在最裡層的函數中,各個變數都能逐級遍歷並輸出。而在倒數第二層的函數中,變數 three 無法遍歷找到,所以輸出了 undefined 。

舉一個通俗點的例子,你準備要花錢買點東西時,會先摸摸自己的錢包,沒了你可以找你爸要,你爸也沒就再找你爺爺,... 。而你爸沒錢買東西時,他並不會來找你要。

閉包在一個函數中,定義另一個函數,稱為函數巢狀。函數的巢狀將形成一個閉包。 閉包與作用域鏈相輔相成,函數的嵌套在產生了鍊式關係的多個作用域的同時,也形成了一個閉包。
複製碼


程式碼如下:


function btargetfunc, 🎜>
function btargetfunc, 🎜>

function btarget function() {

        func.apply(target, arguments);
    };
}

那怎麼理解閉包呢?

外部函數不能存取內嵌函數外部函數也不能存取內嵌函數的參數和變數而內嵌函數可以存取外部函數的參數和變數換一個說法:內嵌函數包含了外部函數的作用域我們再看看之前講述的作用域鏈的例子,這次從閉包的角度來理解下:
複製程式碼 程式碼如下:

var scope = 0, zero = "global-scope";
(function(){
    var scope = 1, one = "scope-1";
 {
        var scope = 2, two = "scope-2";
        (function(){
             // scope-3 scope -2 scope-1 global-scope
            console.log([three, two, one, zero].join(" "));      }) ();
        console.log(typeof three); // undefined
        console.log(scope); // 2
     console.log(scope); // 2
    console.log(scope); // 2
  / undefined
    console.log(scope); // 1
})();
console.log(typeof one); // undefined
console.log(scope); // 0


最裡層的函數能存取到其內部和外部定義的所有變數。而倒數第二層的函數無法存取到最裡層的變量,同時,最裡層的 scope = 3 這個賦值運算並沒有對其外部的同名變數產生影響。

再換個角度來理解閉包:

每次外部函數的調用,內嵌函數都會被創建一次

在它被創建時,外部函數的作用域(包括任何本地變數、參數等上下文), 會成為每個內嵌函數對象的內部狀態的一部分,即使在外部函數執行完並退出後

看下面的例子:

複製代碼 代碼如下:
var i, list = [];
for (i = 0; i     list.push(function(){
        console.log(i);
       console.log(i);
       console.log(i);
   ); forEach(function(func){
  func();
});


我們將得到兩次"2" ,而不是預期的"1" 和"2" ,這是因為在list 中的兩個函數訪問的變量i 都是其上一層作用域的同一個變量。

我們改動下程式碼,以利用閉包來解決這個問題:

複製代碼 代碼如下:
var i, list = [];
for (i = 0; i     list.push((function(j){
        return function(){       return function(){          };
    })(i));
}
list.forEach(function(func){
  func();
});




外層的「立即執行函數」接收了一個參數變數 i ,在其函數內以參數 j 的形式存在,它與被傳回的內層函數中的名稱 j 指向同一個參考。外層函數執行並退出後,參數 j (此時它的值為 i 的當前值)成為了其內層函數的狀態的一部分被保存了下來。
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn