天天看點

console.log的快照

        在日常開發中,我們經常使用console.log來列印資料進行調試,但是console.log的輸出值有時候也不完全準确,或者說并不會達到我們預期的效果

舉個例子(1):

var obj = {}

obj.a = 3;

console.log(obj); // {a:3}
           

當我們在script中編寫如下代碼,浏覽器中會照常列印出我們所期望的資料

但是如果我們這樣呢(2):

var obj = {}
queueMicrotask(()=>{
       obj.a = 3;
});
console.log(obj); 
           

當我們在浏覽器中檢視的時候,我們會看到這樣的景象:

console.log的快照

但是當我們展開之後呢?

console.log的快照

?這是為什麼?

這就和console.log的列印機制有關系了

1、案例(1)中代碼是這樣運作的:

  • 我們建立了一個對象,并且這個對象在記憶體中的引用位址指派給了obj
  • 然後我們修改了obj.a = 3,記憶體位址中的a的值會被設定為3
  • 這個時候,我們使用console.log(obj),console.log會根據obj儲存的記憶體位址去找到obj,最後列印
  • 在浏覽器中正常輸出

2、案例(2)中代碼是這樣運作的:

  • 我們建立了一個對象,并且這個對象在記憶體中的引用位址指派給了obj
  • 然後解析到了queueMicrotask函數,将回調函數添加到了微任務隊列中,等待同步代碼執行完成,JS引擎才會執行微任務隊列中的回調
  • console.log(obj),根據obj的記憶體位址去尋找,由于我們修改obj.a的代碼為一個微任務,是以其實obj現在是一個空對象,再加上我們是立刻執行的一個console.log(),那麼控制台将會輸出一個空對象{}
  • 同步代碼執行完成
  • 開始執行微任務隊列,執行obj.a = 3,obj記憶體位址中的a被修改為3
  • 這個時候我們去檢視控制台,我們就會看到列印的是那個空對象,因為我們列印的其實是console.log的快照!
  • 當我們點選控制台的展開的時候,浏覽器又會根據obj儲存的記憶體位址去尋找堆記憶體中的值,最後,我們就會看到一個被異步(微任務)修改的a:3,

其實總結起來很簡單:

javascript的異步代碼會被添加到任務隊列中(宏/微),當我們修改值的代碼寫在一個異步函數内,console.log不會等待你的異步函數執行完成,它是優先執行的,然後輸出空,然後你的異步函數又修改了obj的記憶體位址中的a,但是console.log已經執行完成了,不會重複執行,是以你看到的還是一個{}對象,但是當我們點選展開的時候,浏覽器又會根據Obj的記憶體位址去找到他的值,最後列印,但是這個時候,你的obj中的a已經被修改為了3,是以會列印3

繼續閱讀