我們知道有個全局的 window對象,js的一切皆window上的屬性和方法。window上有個window.document屬性,記錄了整個html的dom樹,document是頂層。
body 和 head 都是 doc上的一個屬性。
上圖中,head里面的打印結果是null,因為document是按照和我們閱讀文字一樣的方式按順序加載的,並且,當加載到一個script標簽時,會執行其中的代碼,而此時body部分還沒有加載,所以為null。
所以,如果js代碼在doc加載之前要選擇或操作dom時就要寫在 onload的事件回調中,如果不是操作dom,比如做個運算,獲取請求接口數據,就不用關心onload沒有。js放最后也是個辦法,但一般我們應用都比較復雜,既有邏輯運算,也有操作dom,我們可能希望在更早的時候就執行邏輯運算的部分。所以還是想放到head去。
js 是單線程同步執行的,一旦遇到報錯就會退出,中斷執行。
故上面的代碼會報錯,停在第10行。
那如果用函數把第10行包起來呢?
當然,done還是不會打印,即便是一個函數,在調用這個函數時,會按順序執行函數中的代碼,遇到錯誤一樣退出。這些都叫同步執行,所謂同步,就是指,按從上至下的順序執行,一旦遇到錯誤就會退出程序,后面的代碼將不會運行。
當執行到 test()時,會執行函數里的代碼,遇到錯誤就退出了,所以done不會執行打印出來。
js 在運行時,會先全局掃描 var 和 function 聲明的對象。
上面的代碼結果會是什么呢?(in 前面是字符串,后面是對象結構。用來判斷一個對象上是否有前面的鍵值(屬性))
結果是undefined。解釋一下,因為js 先全局掃面了 var,事先var了一個a,這樣window上就有一個a為undefined了,
if (!("a" in window))
那么這個條件判斷的時候,window上就是有一個a的,而且為undefined,既然有a了,那也就不會執行if里的語句了。所以a不會被賦值。上面的代碼拆開來看,真正的執行順序如下:
var 會事先掃描,將聲明的部分 var a; 提取到最前面執行,a = 1; 而賦值的部分依然在原來的位置執行。
下面換一個方式。
效果如下:
最后,感謝大神CX的講解。