問答:
1. CSS和JS在網頁中的放置順序是怎樣的?
CSS一般放置在的<head>標簽中。網頁渲染時,先解析HTML標簽,構建DOM樹,再解析CSS標簽,構建CSSOM樹,然后把DOM和CSSOM組合成渲染樹。如果把CSS放置在底部,那么頁面加載的時候可能會出現白屏或者無樣式內容閃爍(FOUC)。
JS一般放置body標簽的最后面。JS會阻塞加載的,如果放在前面,會影響頁面加載的速度,如果JS文件比較大,算法也比較復雜的話,影響更大。
2. 解釋白屏和FOUC
白屏和無樣式內容閃爍(FOUC)是由于不用瀏覽器加載顯示頁面的機制不同造成的。當把CSS樣式放在底部或者使用@import方式引入樣式時,一些瀏覽器例如chrome,它的加載和渲染機制是等CSS全部加載解析完成后再渲染展示頁面,而這個等待的時間就是白屏。另外一些瀏覽器,如Firefox,它會在CSS未加載前展示頁面,等CSS加載后再重新繪一次,這就造成了FOUC(無樣式內容閃爍)。如果把JS文件放在頭部,腳本會阻塞后面內容的展示和其后組件的下載,也會導致白屏現象。
3. async和defer的作用是什么?有什么區別。
當瀏覽器遇到script腳本的時候:
- 沒有defer和async時,
<script src="script.js"></script>
,瀏覽器會立即加載并執行指定的腳本,“立即”指的是在渲染該script標簽之下的文檔元素之前,也就是說不等待后續載入的文檔元素,讀到就加載并執行。 - 有async,
<script async src="script.js"></script>
,加載和渲染后續文檔元素的過程將和script.js的加載與執行并行進行(異步)。 - 有defer
<script defer src="script.js"></script>
,加載后續文檔元素的過程將和script.js的加載并行進行(異步),但script.js的執行要在所有元素解析完成之后,DOMContentLoaded事件觸發之前完成。
defer和async
藍色線代表網絡讀取,紅色線代表執行時間,這倆都是針對腳本的;綠色線代表 HTML 解析。
此圖告訴我們以下幾個要點:
a. defer 和 async 在網絡讀取(下載)這塊兒是一樣的,都是異步的(相較于 HTML 解析)
b. 它倆的差別在于腳本下載完之后何時執行,顯然defer 是最接近我們對于應用腳本加載和執行的要求的
c. 關于 defer,此圖未盡之處在于它是按照加載順序執行腳本的,這一點要善加利用
d. async 則是一個亂序執行的主,反正對它來說腳本的加載和執行是緊緊挨著的,所以不管你聲明的順序如何,只要它加載完了就會立刻執行
e. 仔細想想,async 對于應用腳本的用處不大,因為它完全不考慮依賴(哪怕是最低級的順序執行),不過它對于那些可以不依賴任何腳本或不被任何腳本依賴的腳本來說卻是非常合適的,最典型的例子:Google Analytics
4. 簡述網頁的渲染機制?
- Create/Update DOM And request css/image/js:瀏覽器請求到HTML代碼后,在生成DOM的最開始階段(應該是Bytes → characters后),并行發起css、圖片、js的請求,無論他們是否在HEAD里。
注意:發起js文件的下載request并不需要DOM處理那個script節點。比如:簡單的正則匹配就能做到這一點,雖然實際上并不一定是通過正則。這是很多人在理解渲染機制的時候存在的誤區。 - Create/Update Render CSSOM:CSS文件下載完成,開始構建CSSOM。
- Create/Update Render Tree:所有CSS文件下載完成,CSSOM構建結束后,和DOM一起生成Render Tree。
- Layout:有了Render Tree,瀏覽器已經能知道網頁中有哪些節點、各個節點的CSS定義以及他們的從屬關系。下一步操作稱之為layout,顧名思義就是計算出每個節點在屏幕中的位置。
- Painting:Layout之后,瀏覽器已經知道了哪些節點要顯示(which nodes are visible)、么個節點的CSS屬性是什么(their computed style)、每個節點在屏幕中的位置是哪里(geometry)。就進入了最后一步:Painting,按照算出來的規則,通過顯卡,把內容畫到屏幕上。
以上五個步驟前3個步驟之所有使用 “Create/Update” 是因為DOM、CSSOM、Render Tree都可能在第一次Painting后又被更新多次,比如JS修改了DOM或者CSS屬性。
Layout 和 Painting 也會被重復執行,除了DOM、CSSOM更新的原因外,圖片下載完成后也需要調用Layout 和 Painting來更新網頁。
5. JavaScript 定義了幾種數據類型? 哪些是簡單類型?哪些是復雜類型?
JavaScript語言的每一個值,都屬于某一種數據類型。JavaScript的數據類型,共有六種:
- 數值(number):整數和小數(比如1和3.14)
- 字符串(string):字符組成的文本(比如“Hello World”)
- 布爾值(boolean):true(真)和false(假)兩個特定值
- undefined:表示“未定義”或不存在,即此處目標沒有任何值
- null:表示空缺,即此處應該由一個值,但目前為空
- object:是一種復雜的數據類型,表示各種值組成的集合
6. NaN、undefined、null分別代表什么?
NaN:非數字值的特殊值。該屬性用于指示某個值不是數字。可以把Number對象設置為該值,來指示不是數字值。這個數值用于表示一個本來要返回數值的操作數未返回數值的情況(這樣就不會拋出錯誤)。注意:NaN與其他數值進行比較的結果總是不相等的,包括它自身在內。
-
undefined:表示不存在值,就是此處目前不存在任何值。典型用法是:
- 變量被聲明了,但沒有賦值時,就等于undefined。
- 調用函數時,應該提供的參數沒有提供,該參數等于undefined。
- 對象沒有賦值的屬性,該屬性的值為undefined。
- 函數沒有返回值時,默認返回undefined。
-
null:表示空值,即該出的值現在為空。典型用法是:
- 作為函數的參數,表示該函數的參數是一個沒有任何內容的對象。
- 作為對象原型鏈的終點。
7. typeof和instanceof的作用和區別?
- typeof:可以用來確定一個變量的數據類型,用來返回操作數類型的字符串。它所返回的結果一般有:布爾:boolean、數字:number、字符串:string、函數:function和undefined:undefined,除此之外,其他情況都返回object。
- instanceof:可以用來確定一個引用類型值是什么類型的對象。instanceof 左操作數是一個類,右操作數是標識對象的類。如果左側的對象是右側類的實例,則返回true。而js中對象的類是通過初始化它們的構造函數來定義的。即instanceof的右操作數應當是一個函數。所有的對象都是object的實例。如果左操作數不是對象,則返回false,如果右操作數不是函數,則拋出typeError。instanceof 運算符是用來測試一個對象是否在其原型鏈原型構造函數的屬性。其語法是object instanceof constructor。instanceof 操作符用來比較兩個操作數的構造函數。只有在比較自定義的對象時才有意義。 如果用來比較內置類型,將會和 typeof 操作符 一樣用處不大。
代碼:
1. 完成如下代碼判斷一個變量是否是數字、字符串、布爾、函數 (難度*)
<pre>
function isNumber(el){
if(typeof el=="number"){
return true;
}
else{
return false;
}
}
function isString(el){
if(typeof el=="string"){
return true;
}
else{
return false;
}
}
function isBoolean(el){
if(typeof el=="boolean"){
return true;
}
else{
return false;
}
}
function isFunction(el){
if(typeof el=="function"){
return true;
}
else{
return false;
}
}
var a = 2,
b = "jirengu",
c = false;
alert( isNumber(a) ); //true
alert( isString(a) ); //false
alert( isString(b) ); //true
alert( isBoolean(c) ); //true
alert( isFunction(a)); //false
alert( isFunction( isNumber ) ); //true
</pre>
2. 以下代碼的輸出結果是?(難度**)
<pre>
console.log(1+1); //2,兩個數相加,輸出數值;
console.log("2"+"4"); //24,兩個字符串相加,輸出字符串;
console.log(2+"4"); //24,一個數值和一個字符串相加,輸出字符串;
console.log(+new Date());//1474425015234,用new Date()參與計算會自動轉換成從1970.1.1到現在的時間的毫秒數;
console.log(+"4");//4,只有一個字符串,會試著將其轉換成數字;
</pre>
3. 以下代碼的輸出結果是? (難度***)
<pre>
var a = 1;
a+++a;//3;a++的運算級高,即(a++)+a;
typeof a+2;//number2;typeof的運算級,先得出typeof a結果是number,再+2,完成一個字符串的拼接;
</pre>
4. 遍歷數組,把數組里的打印數組每一項的平方 (難度**)
<pre>
var arr = [3,4,5]
for(var i = 0; i < arr.length; i++){
console.log(arr[i]*arr[i]);
}// 輸出 9, 16, 25
</pre>
5. 遍歷 JSON, 打印里面的值 (難度**)
<pre>
var obj = {
name: 'hunger',
sex: 'male',
age: 28
}
for (var i in obj) {
console.log(i + ':' +obj[i]);
}// 輸出 name: hunger, sex: male, age:28
</pre>
6. 下面代碼的輸出是? 為什么 (難度***)
<pre>
console.log(a);//undefined;變量a已經被聲明,但是由于變量提升,其值是初始值undefined
var a = 1;//1;a被賦值為1;
console.log(a);//1;a在此之前已經被賦值為1;
console.log(b);//報錯;變量b沒有被定義;
</pre>
本文版權歸本人及饑人谷所有,轉載請注明出處