js 變數的作用域詳解、生存週期,以及一些小細節。

OBKoro1發表於2017-04-28

寫在前面:

是想寫一個閉包的,因為寫的比較細,基於篇幅,所以閉包前面關於變數的部分就單獨發出來,到時候放個連結引進來,js閉包雖然是一個被講爛的東西,但其實很多人剛接觸這個概念也不太懂,所以希望寫一篇接地氣,能夠讓一個從前不知道這個內容的小夥伴能夠清楚的理解閉包這個東西。so,本文是基於閉包的變數部分。

首先需要理解變數的作用域(變數的有效範圍):

變數的作用域有兩種:全域性變數和區域性變數。

全域性變數很好理解:就是我們平時沒有再函式內部宣告的那些變數,在全域性中任何地方(函式,物件等)都可以被引用。

栗子:

var n=999;
  function f1(){
    alert(n);
  }
  f1(); // 輸出999,說明全域性變數n在函式內部被讀取複製程式碼

區域性變數:在函式內部宣告的變數。函式內部的變數,外部無法讀取。
栗子:

 function f1(){
    var n=999;
  }
  alert(n); // 沒有定義,說明函式內部的變數,外部無法讀取。複製程式碼

在函式內部宣告變數沒有使用var,實際上是宣告瞭一個全域性變數,前提是需要先呼叫函式(閉包函式中,也是全域性變數。)!

栗子:

    var func1=function(){
         a1=1;
        console.log(a1); //輸出:1
        function func2() {//func2()是一個閉包
            a2=2;
            console.log(a2);
        }
        func2();//閉包函式中的變數在呼叫函式之後,變數也是全域性變數
        console.log(a2);//輸出2
    };
    func1();//呼叫函式,才會使變數生效
    console.log(a1);//輸出1
     console.log(a2);//輸出2,說明閉包中沒有用var宣告的變數也是全域性變數。複製程式碼

上面栗子中在函式裡面宣告變數沒有用var,在呼叫函式之後,a1,a2都能有效輸出,看完栗子之後,相信你們對變數的作用域也有一些瞭解了,我們總結一下:


變數作用域,js高階程式設計(紅寶書)中的解釋:

內部環境可以通過作用域鏈訪問所有的外部環境,但外部環境不能訪問內部環境中的任何變數和函式。這些環境是線性、有次序的。每個環境都可以向上搜尋作用域鏈,以查詢變數和函式名;

意思就是:比如函式的區域性環境可以訪問到外界所有的變數的函式,而且環境的搜尋是先從自己本身的環境開始,一級一級往上搜尋,這樣由多個執行上下文的變數物件構成的連結串列就叫做作用域鏈。

關於查詢變數,紅寶書中有一句話是這樣的:

識別符號解析是沿著作用域鏈一級一級地搜尋識別符號的過程。搜尋過程始終從作用域鏈的前端開始,然後逐級的向後查詢,直至找到識別符號位置(如果找不到識別符號,通常會導致錯誤的發生、)

ps:識別符號指的是變數的名字,作用域鏈的前端指的是當前執行程式碼所在環境的變數物件。

作用域鏈的用途:

保證對執行環境有權訪問的所有變數和函式的有序訪問

紅寶書中的作用域鏈栗子:

var color = 'blue';

function text1(){
    var anotherColor = 'red';

    function text2(){
        var tempCplor = anotherColor;
        anotherColor = color;
        //這裡可以訪問到color、anotherColor和tempColor
    }
    //這裡可以訪問color和anotherColor,但不能訪問到tempColor
    text2();
}
//這裡只能訪問到color
text1();複製程式碼

解析(畫重點,這裡關於作用域講的比較詳細,看完這個作用域就瞭解差不多):

以上程式碼一共涉及三個執行環境:全域性環境,text1()的區域性環境和text2()的區域性環境。

1.全域性環境中有一個變數color和一個函式text1()。

2.text1()的區域性環境中有一個anotherColor變數和一個text2()的函式,但它可以訪問到全域性環境中的變數color。

3.text2()的區域性環境有一個變數tempColor,該變數只能在text2()自身的環境中被訪問到。這是一個閉包,無論是全域性環境還是text1()的區域性環境都無權訪問tempColor。但是在text2()的內部環境中,可以訪問到全域性環境和text1()中的所有變數,因為這兩個環境是text2()的父執行環境。

這個作用域鏈為:

js 變數的作用域詳解、生存週期,以及一些小細節。
只是把函式的名字改了,圖方便

ps:函式引數也被當做變數來對待,因此其訪問規則與執行函式中的其他變數相同。

以上出自紅寶書,自己修改了一丟丟,紅寶書還是神器啊,常看常新,每次都會有新發現。


關於變數的生存週期:

1.全域性變數的生存週期是永久的,除非我們主動銷燬。

ps:變數永久生存,且可以隨時呼叫,但是使用的時候要適度,正是因為它的生命週期長,所以將佔據更多的記憶體,如果宣告的變數都是全域性變數,當專案比較大的時候,就可能出現效能問題,養成一個好的習慣還是有必要的。

2.而對於在函式內用 var 關鍵字宣告的區域性變數來說,當退出函式時,這些區域性變數即失去了它們的價值,它們都會隨著函式的呼叫的結束而銷燬。

ps:呼叫函式結束,區域性變數確實會銷燬。但並不是完全銷燬,而是一直函式的內部環境中存活著,當函式再度被呼叫時,變數就“復活”了,所以區域性變數還是非常方便的,不會影響二次使用。

值得注意的是:在區域性環境中,出現全域性變數與區域性變數重名的時候,起作用的是區域性變數,全域性變數被遮蔽掉。這是因為上文說過作用域鏈的原因,先由區域性開始搜尋變數,當區域性找到該變數的時候,就不會再我繼續往父級找變數了。


後話:

就這些吧,覺得內容不夠多,平常多一點的。本來想寫個面試題的,後來幾經修改,覺得寫的不好,就刪掉了。這幾天五一,爭取把閉包這個東西寫出來,寫的不好之處,歡迎指導。

最後:碼字不易,感謝支援!因為我經常看不懂別人寫的分享,所以個人寫文比較偏小白,寫的不好之處,歡迎指點。然後就是希望看完的朋友點個喜歡,也可以關注一下我。
ps:目前待業,座標北京,本人適應網際網路快節奏,高強度,持續學習,持續成長,認真,嚴謹,學習積極性強。中小公司大佬求帶走,郵箱:1677593011@qq.com。
掘金個人主頁簡書主頁連結csdn部落格主頁連結

相關文章