概念
1、CSS和JS在網(wǎng)頁上的放置順序是怎樣的?
- 將CSS放在head標(biāo)簽中:CSS放在后面會(huì)造成白屏或者FOUC;
- 將JS放在最后:腳本會(huì)阻塞后面內(nèi)容的呈現(xiàn)和其后組件的下載,所以JS放在頁面的頂部也會(huì)造成白屏的現(xiàn)象;
- 這樣做主要是從用戶體驗(yàn)和性能去考慮的。
2、解釋白屏和FOUC
如果樣式放在頭部,不管瀏覽器是加載到什么時(shí)候再解析還是等全部都加載后再解析,都可以在最快的時(shí)間把渲染樹給得到,CSSOM一開始就有了,只要等你內(nèi)容來了,我馬上就可以給它加上,就不會(huì)存在這些現(xiàn)象。
-
白屏現(xiàn)象樣式
- 瀏覽器A(比如chrome)如果獲取到的內(nèi)容沒有CSS樣式時(shí),那這些無樣式內(nèi)容就不會(huì)被渲染,所以這時(shí)候就會(huì)出現(xiàn)白屏現(xiàn)象。
- 在IE瀏覽器當(dāng)中,如果把樣式放在底部,在一些場(chǎng)景當(dāng)中,比如刷新頁面、新窗口打開等,頁面就會(huì)出現(xiàn)白屏,而不是內(nèi)容逐步展現(xiàn)。
- 如果使用
@import
標(biāo)簽,即使CSS放入link當(dāng)中且也放在頭部,也有可能會(huì)出現(xiàn)白屏現(xiàn)象。
- 對(duì)于圖片和CSS,在加載時(shí)會(huì)并發(fā)加載,然而在加載JS文件時(shí)會(huì)禁用并發(fā),阻止其他內(nèi)容的下載。所以把JS代碼放在頁面頂部也會(huì)造成白屏現(xiàn)象。
- 瀏覽器A(比如chrome)如果獲取到的內(nèi)容沒有CSS樣式時(shí),那這些無樣式內(nèi)容就不會(huì)被渲染,所以這時(shí)候就會(huì)出現(xiàn)白屏現(xiàn)象。
-
FOUC(Flash Of Unstyled Content)無樣式內(nèi)容閃爍
- 瀏覽器B(比如firefox)是逐步加載無樣式的內(nèi)容,等CSS加載完成后頁面突然展現(xiàn)的樣子。也就是說,瀏覽器加載了無樣式內(nèi)容,又突然解析到了樣式,會(huì)對(duì)頁面進(jìn)行重新的渲染,這時(shí)候就會(huì)產(chǎn)生FOUC現(xiàn)象;
- 在IE瀏覽器中,如果把樣式放在底部,某些場(chǎng)景下(點(diǎn)擊鏈接、輸入U(xiǎn)RL、使用書簽進(jìn)入等等),就會(huì)出現(xiàn)FOUC現(xiàn)象。對(duì)于 Firefox 則會(huì)一直表現(xiàn)出 FOUC。
總結(jié)就是:
1、樣式如果放最后,對(duì)于Chrome就會(huì)白屏,對(duì)于Firefox就會(huì)FOUC,IE就比較奇葩,都有可能發(fā)生。
2、JS如果放在最開頭,那就會(huì)白屏。
3、async和defer的作用是什么?有什么區(qū)別
頁面中一個(gè)js文件的完整引入流程:
1、引入js文件包括加載、解析和執(zhí)行3個(gè)階段;
2、加載js默認(rèn)是同步加載(阻塞加載);
3、加載完js文件后,根據(jù)響應(yīng)頭信息的內(nèi)容類型Content-Type:application/x-javascript
進(jìn)行js文件的解析(預(yù)處理階段),js引擎首先會(huì)解析所有的腳本,然后進(jìn)行變量提升,此時(shí)遇到錯(cuò)誤將不報(bào)錯(cuò);
4、執(zhí)行js文件,按照腳本和代碼出現(xiàn)的先后順序執(zhí)行,并且遇到錯(cuò)誤報(bào)錯(cuò);延遲腳本(執(zhí)行階段)
<script src= 'demo.js' defer></scirpt>
上述外部js文件的引入使用了script元素的defer屬性,它將會(huì)改變script元素引入流程過程中的執(zhí)行階段,即延遲執(zhí)行該腳本,直到頁面其他內(nèi)容解析和渲染完畢;
- 異步腳本(加載階段)
<script src='demo.js' async></script>
上述外部js文件的引入使用了script元素的async屬性,它將會(huì)改變scirpt元素引入流程過程中的加載階段,即異步腳本加載過程中不影響頁面其他的操作;
如果你在頁面中使用兩個(gè)以上的異步腳本,那么一定要確保二者不存在依賴,不然可能會(huì)導(dǎo)致錯(cuò)誤;
- 比較async和defer
- 相同點(diǎn)
- 加載文件時(shí)不會(huì)阻塞頁面的渲染
- 只對(duì)外部腳本文件有效
- 相同點(diǎn)
- 不同點(diǎn)
- async不保證按照指定它們的先后順序執(zhí)行;
- defer腳本延遲到文檔解析和顯示后執(zhí)行,會(huì)按照原本給出的順序先后執(zhí)行。
4、簡(jiǎn)述網(wǎng)頁的渲染機(jī)制
- 解析HTML以構(gòu)建DOM樹及CSSOM樹,將標(biāo)簽轉(zhuǎn)化為內(nèi)容樹中的DOM節(jié)點(diǎn),接著把外部引用的CSS文件和style標(biāo)簽中的樣式信息解析為CSSOM樹;
- 構(gòu)建渲染樹(render樹),由DOM樹及CSSOM樹構(gòu)建而成;
- 布局render樹,在render樹的基礎(chǔ)上進(jìn)行布局過程,它將確定每個(gè)節(jié)點(diǎn)在屏幕上的確切坐標(biāo);
- 繪制render樹,把每個(gè)節(jié)點(diǎn)繪制到屏幕上;
下面是chrome瀏覽器渲染網(wǎng)頁的機(jī)制:構(gòu)建好DOM樹和CSSOM樹之后再去構(gòu)建渲染樹(也是白屏現(xiàn)象的原因);
有空看看:瀏覽器內(nèi)部工作原理
5、JavaScript定義了幾種數(shù)據(jù)類型?哪些是簡(jiǎn)單類型?哪些是復(fù)雜類型?
這種分法是從存儲(chǔ)的角度來講的,ECMAScript中有5種簡(jiǎn)單數(shù)據(jù)類型(也稱為基本數(shù)據(jù)類型):Undefined、Null、Boolean、Number和String;還有一種復(fù)雜數(shù)據(jù)類型Object,Object本質(zhì)上是由一組無序的名值對(duì)組成的。
1、Undefined類型:
Undefined類型只有一個(gè)值,即undefined。意為未定義或不存在;
- 在使用var聲明變量但未對(duì)其加以初始化時(shí),這個(gè)變量的值就是undefined。
var message; //這個(gè)變量聲明之后默認(rèn)取得了undefined值
alert(message); //"undefined"
alert(age); //會(huì)報(bào)錯(cuò)
運(yùn)行上面的代碼,變量message只有一個(gè)值,即“undefined”。
- 對(duì)未初始化的變量執(zhí)行typeof操作符會(huì)返回undefined值,而對(duì)未聲明的變量執(zhí)行typeof操作符同樣也會(huì)返回undefined值。
var message; //這個(gè)變量聲明之后默認(rèn)取得了undefined值
alert(typeof message); //"undefined"
alert(typeof age); //"undefined"
2、Null類型:
Null類型也只有一個(gè)值,即null。表示空缺,即此處應(yīng)該有一個(gè)值,但目前為空。null值表示空對(duì)象指針,這也是使用typeof檢測(cè)null值時(shí)會(huì)返回"object"的原因。
var car = null;
alert(typeof car); //"object"
3、Boolean類型:
該類型有兩個(gè)字面值:ture和false。
可以對(duì)任何數(shù)據(jù)類型的值調(diào)用Boolean()函數(shù),而且總會(huì)返回一個(gè)Boolean值,下面是轉(zhuǎn)換規(guī)則:
數(shù)據(jù)類型 | 轉(zhuǎn)換為ture的值 | 轉(zhuǎn)換為false的值 |
---|---|---|
Boolean | ture | false |
String | 任何非空字符串 | ""(空字符串) |
Number | 任何非零數(shù)字值(包括無窮大) | 0和NaN |
Object | 任何對(duì)象 | null |
Undefined | 不適用 | undefined |
4、Number類型:
- 整數(shù)(十進(jìn)制,八進(jìn)制,十六進(jìn)制)
- 浮點(diǎn)數(shù)(用科學(xué)計(jì)數(shù)法表示,相加不精確,數(shù)值范圍isFinite()函數(shù))
-
NaN,非數(shù)值是一個(gè)特殊的數(shù)值,用來表示一個(gè)本來要返回?cái)?shù)值的操作數(shù)未返回?cái)?shù)值的情況。
返回NaN的情況
值NaN有兩個(gè)特點(diǎn):(isNaN()函數(shù))
- 任何涉及NaN的操作都會(huì)返回NaN;
- NaN與任何值都不相等,包括NaN本身,如
alert(NaN == NaN); //false
會(huì)返回false;
對(duì)于非數(shù)值可以用三個(gè)函數(shù)轉(zhuǎn)換為數(shù)值:Number()、parseInt()、parseFloat()
。
Number()
可以用于任何數(shù)據(jù)類型,規(guī)則相當(dāng)復(fù)雜而且不合理,幾乎不使用,常用的是后兩個(gè),專門用于把字符串轉(zhuǎn)換為數(shù)值,規(guī)則類似:
- 忽略字符串前面的空白字符,找到第一個(gè)非空白字符;
- 如果第一個(gè)字符不是 - 或者數(shù)字返回NaN;
- 如果是繼續(xù)解析,直到非數(shù)值模式為止;
- 0開頭會(huì)當(dāng)作八進(jìn)制,0x開頭會(huì)當(dāng)作十六進(jìn)制,但是可以指定第二個(gè)參數(shù)指定基數(shù)
5、String類型:
字符串,可以由單引號(hào)或雙引號(hào)表示。
要把一個(gè)值轉(zhuǎn)換為一個(gè)字符串有兩種方法:toString()方法、String()轉(zhuǎn)型函數(shù);
- 幾乎每個(gè)值都有toString()方法,除了null和undefined值之外;
-
在不知道要轉(zhuǎn)換的值是不是null或undefined的情況下使用String();
轉(zhuǎn)換為字符串
6、Object對(duì)象類型:
JavaScript的所有數(shù)據(jù)都可以被視為對(duì)象,這也是我們常說的一切皆為對(duì)象。
對(duì)象類型,較為復(fù)雜,意為一組數(shù)據(jù)和功能的集合,包含屬性和方法。
所以只要包含屬性和功能的一個(gè)集合就可以稱為Object類型,比如,數(shù)組、函數(shù)、“標(biāo)準(zhǔn)”的對(duì)象、時(shí)間對(duì)象、基本包裝對(duì)象、兩個(gè)單體內(nèi)置對(duì)象、正則表達(dá)式都是Object類型。
阮一峰的這個(gè)講得特別好理解:數(shù)據(jù)類型
6、NaN、undefined、null分別代表什么?
-
NaN,非數(shù)值是Number類型中一個(gè)特殊的數(shù)值,用來表示一個(gè)本來要返回?cái)?shù)值的操作數(shù)未返回?cái)?shù)值的情況。
返回NaN的情況
針對(duì)NaN的這兩個(gè)特點(diǎn),ECMAScript定義了isNaN()函數(shù)。它只有一個(gè)參數(shù),這個(gè)參數(shù)可以是任何類型,該函數(shù)會(huì)幫我們確定這個(gè)參數(shù)是否“不是數(shù)值”。isNaN()接收到一個(gè)值之后,會(huì)嘗試將這個(gè)值轉(zhuǎn)換為數(shù)值。
- Undefined數(shù)據(jù)類型:
Undefined類型只有一個(gè)值,即undefined。意為未定義或不存在; - 在使用var聲明變量但未對(duì)其加以初始化時(shí),這個(gè)變量的值就是undefined。
var message; //這個(gè)變量聲明之后默認(rèn)取得了undefined值
alert(message); //"undefined"
alert(age); //會(huì)報(bào)錯(cuò)
運(yùn)行上面的代碼,變量message只有一個(gè)值,即“undefined”。
- 對(duì)未初始化的變量執(zhí)行typeof操作符會(huì)返回undefined值,而對(duì)未聲明的變量執(zhí)行typeof操作符同樣也會(huì)返回undefined值。
var message; //這個(gè)變量聲明之后默認(rèn)取得了undefined值
alert(typeof message); //"undefined"
alert(typeof age); //"undefined"
- Null數(shù)據(jù)類型:
Null類型也只有一個(gè)值,即null。表示空缺,即此處應(yīng)該有一個(gè)值,但目前為空。null值表示空對(duì)象指針,這也是使用typeof檢測(cè)null值時(shí)會(huì)返回"object"的原因。
var car = null;
alert(typeof car); //"object"
實(shí)際上undefined的值是派生自null值的:
7、typeof和instanceof的作用和區(qū)別?
因?yàn)镋CMAScript是松散型的,所以需要一種手段來檢測(cè)給定變量的數(shù)據(jù)類型。JS中有三種方法來確定一個(gè)值到底是什么類型。分別為:typeof運(yùn)算符、instanceof運(yùn)算符以及Object.prototype.toString()方法。
- typeof運(yùn)算符可以返回一個(gè)值的數(shù)據(jù)類型,可能有以下結(jié)果:
-
原始類型
原始類型 -
undefined類型
undefined返回undefined。
undefined類型
利用這一點(diǎn),typeof可以用來檢查一個(gè)沒有聲明的變量,而不報(bào)錯(cuò)。
測(cè)試 - 函數(shù)
函數(shù)返回function。
-
// 定義一個(gè)空函數(shù)
function f(){}
typeof f; // "function"
- 其它
除此之外都返回object
從上面代碼可以看到,空數(shù)組([])的類型也是object,這表示在JavaScript內(nèi)部,數(shù)組本質(zhì)上只是一種特殊的對(duì)象。另外,null的類型也是object,這是由于歷史原因造成的,為了兼容以前的代碼,后來就沒法修改了,并不是說null就屬于對(duì)象,本質(zhì)上null是一個(gè)類似于undefined的特殊值。
-
instanceof則為判斷一個(gè)對(duì)象是否為某一數(shù)據(jù)類型,或一個(gè)變量是否為一個(gè)對(duì)象的實(shí)例,返回Boolean類型。
對(duì)于用typeof判斷都為Object的對(duì)象我們就可以用instanceof加以判斷:
結(jié)果
JavaScript instanceof 運(yùn)算符深入剖析
代碼
1、完成如下代碼判斷一個(gè)變量是否是數(shù)字、字符串、布爾、函數(shù)
function isNumber(el){
if( typeof el === "number" ){
return ture;
}else{
return false;
}
}
function isString(el){
if( typeof el === "string" ){
return ture;
}else{
return false;
}
}
function isBoolean(el){
if( typeof el === "boolean" ){
return ture;
}else{
return false;
}
}
function isFunction(el){
if( typeof el === "function" ){
return ture;
}else{
return false;
}
}
var a = 2,
b = "zhouhuahua",
c =false;
alert( isNumber(a) );
alert( isString(a) );
alert( isString(b) );
alert( isBoolean(c) );
alert( isFunction(a) );
alert( isFunction( isNumber ) );
2、以下代碼的輸出結(jié)果是?
console.log(1+1); //2,兩個(gè)數(shù)相加,輸出數(shù)值;
console.log("2"+"4"); //"24",兩字符串拼接,輸出字符串;
console.log(2+"4"); //"24",一個(gè)數(shù)值和一個(gè)字符串相加,輸出字符串;
console.log(+new Date()); // 1471048600952,用new Date()參與計(jì)算會(huì)自動(dòng)轉(zhuǎn)換為從1970.1.1到現(xiàn)在的時(shí)間的毫秒數(shù)。
console.log(+"4"); // 4,在只有一個(gè)字符串時(shí),會(huì)嘗試將其轉(zhuǎn)換為數(shù)字;
在JavaScript中運(yùn)算符通常會(huì)根據(jù)需要對(duì)操作數(shù)進(jìn)行類型轉(zhuǎn)換,乘法操作符希望操作數(shù)是數(shù)字,但是 "3" * "5"也是合法的,JavaScript會(huì)自動(dòng)將其轉(zhuǎn)換為數(shù)字計(jì)算,返回Number 15;對(duì)減法也是一樣的。
不過有些操作符對(duì)不同的數(shù)據(jù)類型有不同的含義,比如 +:
- 在兩個(gè)操作數(shù)都是數(shù)字的時(shí)候,會(huì)做加法運(yùn)算;
- 兩個(gè)參數(shù)都是字符串或在有一個(gè)參數(shù)是字符串的情況下會(huì)把另外一個(gè)參數(shù)轉(zhuǎn)換為字符串做字符串拼接;
- 在參數(shù)有對(duì)象的情況下會(huì)調(diào)用其valueOf或toString方法;
- 在只有一個(gè)字符串參數(shù)的時(shí)候會(huì)嘗試將其轉(zhuǎn)換為數(shù)字;
-
在只有一個(gè)數(shù)字參數(shù)的時(shí)候返回其正數(shù)值;
加法操作符
3、以下代碼的輸出結(jié)果是?
var a = 1;
a+++a;
typeof a+2;
在a+++a表達(dá)式當(dāng)中,后置遞增的優(yōu)先級(jí)最高。所以相當(dāng)于(a++)+a。a一開始賦值為1,a++表示先賦值再自增,所以a++的計(jì)算結(jié)果為1,且此時(shí)a等于2。所以a+++a表達(dá)式的計(jì)算結(jié)果為3。
而typeof a+2中,typeof的優(yōu)先級(jí)比“+”高,所以它會(huì)先計(jì)算typeof a,得到的輸出是字符串"number"。然后是一個(gè)字符串加上一個(gè)數(shù)字,會(huì)把數(shù)字轉(zhuǎn)換成字符串。所以得到的輸出為"number2"的字符串。
4、遍歷數(shù)組,把數(shù)組里的打印數(shù)組每一項(xiàng)的平方
var arr =[3,4,5];
/* for(key in arr){
console.log(arr[key]*arr[key]);
} */
for(i=0;i<arr.length;i++){
console.log(arr[i]*arr[i]);
}
5、遍歷JSON,打印里面的值
var obj = {
name: "hunger",
sex: "male",
age: 28
}
for(k in obj){
console.log( k+":"+obj[k] ) ;
}
6、下面代碼的輸出是?為什么
console.log(a);
var a = 1;
console.log(a);
console.log(b);
JavaScript引擎的工作方式是,先解析代碼,獲取所有被聲明的變量,給他初始值undefined,然后再一行一行地運(yùn)行。這造成的結(jié)果,就是所有的變量的聲明語句,都會(huì)被提升到代碼的頭部,這就叫做變量提升。
上面的代碼相當(dāng)于如下代碼:
var a;
console.log(a);
a = 1;
console.log(a);
console.log(b);
(完)