天天看點

javascript 棧記憶體、堆記憶體、作用域、變量(變量提升ES5)全面了解之間的關系(1)

javascript 棧記憶體、堆記憶體、作用域、變量(變量提升ES5)确實是js中比較難懂的隻是點。

javascript 中有三座大山,學習起來很是吃力。

第一座: 作用域和上下文環境

第二座: 原型和原型鍊

第三座:單線程和異步,

今天我帶大家翻越這第一座大山。希望本文能讓你對作用域和變量提升有個新的認識

在這之前

一.先普及下基本知識和下文需要用到的知識點

console.log(window.a) //undefined 
//以上判斷無法确定a是不是window 的屬性
//是以可以通過 console.log("a" in window) in 的方式來檢查一個屬性是不是屬于該對象
           
VAR a = b = c = 1
//等于
var a = 1;
b = 1;
c = 1
           
var a, b, c = 1
//等于 
var a;
var b;
var c = 1;
           
//先++和後++的差別
var i = 10;
console.log(i++) //10
console.log(++i) //12 
           
//基本資料類型和引用資料類型的差別
var a = 12;
var b = a;
b = 13;
console.log(a); // 12

var arr = [100, 23]
var brr = arr;
brr = [100, 200]
console.log(arr); // [100, 200]

// 總結:
// 對象的定義:
// 1. 開辟一個堆記憶體
// 2. 把鍵值對存儲到這個堆記憶體中
// 3. 把這個空間位址指派給變量名;
           
//null 和 undefined都表示沒有
    // null 表示空對象指針;

    // null 的幾種情況
    // 1. 通過id擷取元素如果擷取不到内容,那麼預設傳回值是null;
    // 2. 如果需要銷毀對象的堆記憶體,那麼給對象指派為null;
    // 3. 正則進行捕獲,捕獲不到内容,那麼傳回值是null;

    // undefined 的幾種情況
    // 1. 如果變量隻聲明,沒有指派,那麼預設存儲的值就是undefined;
    // 2. 如果擷取對象的屬性名對應的屬性值,如果屬性名不存在,擷取的值是undefined;
    // 3. 如果函數的形參沒有對應的實參,那麼形參預設存儲的值是undefined
    // 4. 如果函數沒有return,那麼預設的傳回值也是undefined;
	// typeof a //undefined (如果a沒有被聲明 就會産生 暫行性死區)
           

關于null 和 undefined 深入了解可以看我之前的文章:

https://blog.csdn.net/wulove52/article/details/84964313

如果上面的東西你都有所了解了,那麼們接着往下看。

二. 先整體列出一些關鍵詞,看看大家了解多少。然後我們在一個個關鍵詞的進行說明

基本資料類型、引用資料類型、棧記憶體、堆記憶體、作用域 全局作用域 私有作用域 塊級作用域(ES6私有作用域的一種)、作用域鍊、全局變量、私有變量、變量提升、函數執行過程、暫時性死區

JS中的記憶體 分為堆記憶體 和棧記憶體

棧記憶體:提供JS代碼執行的環境和存儲基本類型值

堆記憶體:存儲引用資料類型值(對象:鍵值對 函數:代碼字元串)

棧記憶體釋放:

    一般情況下,當函數執行完成,所形成的私有作用域(棧記憶體)都會自動釋放掉

    (在棧記憶體中存儲的值也都會釋放掉)

    但是也有特殊情況不銷毀的情況:

    1.函數執行完成,目前形成的棧記憶體中,某些内容被棧記憶體一歪的變量占用了,此時棧記憶體不能釋放(一旦釋放

    外面找不到原有的内容了)

    2.全局棧記憶體隻有在頁面關閉的時候才會被釋放掉

    如果目前棧記憶體沒有被釋放,那麼之前在棧記憶體中存儲的基本值也不會被釋放,能夠一直保持下來

堆記憶體釋放

    讓所有引用堆記憶體空間位址的變量指派為null即可(沒有變量占用,流覽器會在空閑時候把它釋放掉)

作用域:就是指在棧記憶體中形成的代碼運作環境

作用域分為 全局作用域 和 私有有作用域 和 塊級作用域(ES6)

全局作用域

定義:當代碼運作,那麼浏覽器會給代碼提供一個全局的運作環境,那麼這個環境就是全局作用域

特點:

1.一個頁面隻有一個全局作用域

2. window : window是全局作用域最大的一個對象;

銷毀情況:

1.頁面關閉或重新整理

私有作用域

定義:函數執行會形成一個新的私有的作用域

特點:

    1.私有作用域在全局作用域中形成,具有包含的關系;

    2.在一個全局作用域中,可以有很多個私有作用域

銷毀情況:

1.函數執行完畢就銷毀 fn()

2.函數執行完畢暫時不銷毀 fn()()

3.函數執行完成不銷毀

  1)函數傳回一個對象

  2)并且傳回的對象被其他變量引用

塊級作用域 (ES6)

定義:由特定代碼塊形成一個作用域

特點:

    1.塊級作用域是es6中新引入的一種作用域;

    2.JS中常見到的if{}  for{}  while {}  try{} catch{}  switch  case{} 都是塊級作用域

    3.var obj = {};// 這不是一個塊級作用域;

    4.也具有私有作用域的特點,是私有作用域的一種

作用域鍊:

定義:如果目前作用沒有聲明就會向上級查找沒找到之前,一直向上查找知道到全局作用域下,這樣的查找軌迹叫做作用域鍊

注意:

1.在私有作用下沒有通過var 但是被指派了。在作用域鍊中查到到全局也沒有找到該變量。那麼該變量會提升為全局變量

2.一個函數的上級作用域是誰,和他在哪裡執行沒有關系和在哪裡建立(定義)的有關系,在哪裡建立的,他的上級作用域就是誰

全局變量:

定義:在全局作用域下可以使用的變量就是全局變量

特點:

    1.在私有作用域中是可以擷取到全局變量的,但是在全局作用域中不能擷取私有變量的;

    2.如果是全局變量,都會給window新增一個鍵值對;屬性名就是變量名,屬性值就是變量名所存儲的值;

    3.如果變量隻被var過,那麼存儲值是undefined;

    4.在私有作用下沒有通過var 但是被指派了。在作用域鍊中查到到全局也沒有找到該變量。那麼該變量會提升為全局變量

私有變量:

定義:定義:私用作用域下定義的變量就是私有變量;

特點:外層作用域是擷取不到私有作用域下的變量

哪些情況屬性私有變量:

      1.私有作用域的實參,

      2.私有作用域下用var 聲明的變量

      3.私有作用域下聲明的函數function

變量提升:

定義:在目前作用域下,把帶var和function進行提前的聲明(提前通知有這個變量),帶var的隻聲明不定義,帶function的不僅聲明而且還要定義(指派)

特點:

    1.浏覽器會過濾整個檔案中代碼,把帶var和function給篩選出來;把篩選出變量放到目前作用域的最上端;

    2.如果變量隻聲明,沒有定義,那麼預設存儲值是undefined;

    3.函數的定義是發生在變量提升階段;

    4.變量提升隻發生在目前作用域

變量提升的幾種情況:

   1.不管條件是否成立,都要進行變量提升;

        1). 在最新版本浏覽器中,在塊級作用中,不管條件是否成立,帶function隻聲明不定義;

        2) : 在老版本浏覽器中,不僅聲明而且定義;

    2. 變量提升隻發生在等号的左邊;

    3. 函數體中return後面的内容不需要變量提升,但是return下面的内容需要變量提升;

    4.如果變量名重複,不再進行重複聲明,但要重新定義;

    5.自執行函數不進行變量提升

    6.let const

        1)let 和const都是es6新增的定義變量的文法;

        2)let和const定義的變量是不進行變量提升的;

        3)let 聲明的變量不可以重名;

        4) const : 定義一個常量;

函數的執行過程:

1.形成私有作用域(運作環境 棧記憶體)

2.形參指派

3.變量提升(被var 的變量和函數function)

4.代碼按順序執行

5.作用域是否銷毀

閉包

函數執行形成一個私有的作用域,保護裡面的私有變量不受外界幹擾,這種保護機制稱之為閉包

市面上:形成不銷毀的私有作用域(私有棧記憶體)才是閉包

閉包的作用:

1.閉包具有“保護”作用

2.閉包具有“儲存”作用

暫時性死區

typeof a  //undefined 在原有浏覽器渲染機制下,基于typeof等邏輯運算符檢測一個未被聲明的變量 ,不會報錯

如果是用let 聲明的變量用typeof檢測 就會報錯,這就解決了浏覽器暫行性死區問題

帶var和不帶var的差別

1.不帶var不進行變量提升

2.不帶var的本質就是window的一個屬性

ES6中的let

1.在ES6中基于let/const聲明的變量,不存在變量提升

2.不會和window屬性映射

3.在相同作用域,如果是let聲明的變量不能提前使用。也不能重複聲明

4.在相同作用域,如果是let聲明的變量。就不能再用var聲明了

5.let聲明的變量會會形成塊級作用域(類似于私有作用域)

說明:也就是在代碼運作之前會做文法檢查

實踐是檢驗真理的唯一标準,下一篇我會拿一些常用的題來實際解讀。

繼續閱讀