天天看點

前端面試技巧頁面布局CSS盒模型DOM事件HTTP協定類原型鍊面向對象通信類浏覽器渲染機制頁面性能安全類結語

9月底秋招結束後,一直玩到今天。這篇部落格在9月份就想寫來着,可那段時間太忙了,一天最多做過四個筆試,面試三家公司,确實沒有精力再寫部落格了。這篇部落客要針對前端面試高頻問題,網上關于前端面試的題目有很多,但是很多題目過于陳舊,并不會被問到。以下内容是我親身經曆面試時經常被問到的點和如何回答的,希望給以後找工作的同學一點參考。在此也要感謝慕課網的《前端跳槽面試必備技巧》這門課程,如果有興趣的同學可以購買視訊課程學習。

目錄

  • 頁面布局
    • 三列布局
    • 盒子水準垂直居中
    • BFC
    • 浮動
  • CSS盒模型
  • DOM事件
  • HTTP協定類
  • 原型鍊
  • 面向對象
    • 類的聲明
    • JS 繼承
  • 通信類
    • 同源政策及限制
    • 前後端通信的方式
    • 跨域
  • 浏覽器渲染機制
    • 浏覽器渲染過程
    • 重繪和重排
    • 浏覽器輸入URL後發生了什麼?
  • 頁面性能
  • 安全類
  • 結語

頁面布局

頁面布局主要包括:三列布局、盒子水準垂直居中、BFC、浮動等内容。

三列布局

左中右三列布局實作的頁面效果:左右寬度已知,中間寬度自适應。 實作方法很多,至少說出以下幾種方法,除了實作以外,各種方法的優缺點也要知道。廢話不多說,直接上代碼。

  1. 浮動
<div class="con">
	<div class="left">left</div>
	<div class="right">right</div>
	<div class="center">center</div>
</div>
           
.con div{
		height: 500px;
	}
	.left{
		float: left;
		width: 300px;
		background: yellow;
	}
	.right{
		float: right;
		width: 300px;
		background: red;
	}
	.center{
		background: blue;
	}
           

缺點:浮動會脫離文檔流

優點:相容性好

  1. 絕對定位
<div class="con">
	<div class="left">left</div>
	<div class="right">right</div>
	<div class="center">center</div>
</div>
           
.con div{
		height: 500px;
	}
	.left{
		position: absolute;
		left: 0;
		width: 300px;
		background-color: red;
	}
	.right{
		position: absolute;
		right: 0;
		width: 300px;
		background-color: red;
	}
	.center{//寬度不設定
		position: absolute;
		left: 300px;//關鍵
		right: 300px;
		background-color: yellow
	}
           

優點:快捷

缺點:脫離文檔流,可使用性較差

說到定位,很有可能問

position

屬性值又哪些?有什麼差別?

前端面試技巧頁面布局CSS盒模型DOM事件HTTP協定類原型鍊面向對象通信類浏覽器渲染機制頁面性能安全類結語

3. Flex布局

<div class="con">
	<div class="left">left</div>
	<div class="center">center</div>
	<div class="right">right</div>
</div>
           
.con{
		height: 100px;
		display: flex;
	}
	.left{
		width: 300px;
		background-color: red
	}
	.right{
		width: 300px;
		background-color: blue;
	}
	.center{
		flex:1;//中間自适應原理
		background-color: yellow
	}
           
缺點:相容性
  1. table布局
<div class="con">
	<div class="left">left</div>
	<div class="center">center</div>
	<div class="right">right</div>
</div>
           
.con{
		height: 100px;
		width: 100%;
		display: table;
	}
	.left{
		width: 300px;
		display: table-cell;
		background-color: red
	}
	.right{
		width: 300px;
		display: table-cell;
		background-color: blue;
	}
	.center{
		display: table-cell;
		background-color: yellow
	}
           

盒子水準垂直居中

  1. 定位
父級相對定位,子級絕對定位,子級left\right\top\bottom設定為0,margin:auto
<div class="con">
	<div class="center">center</div>	
</div>
           
.con{
	width: 400px;
	height: 400px;
	position: relative;
	background-color: blue;
}
.center{
    width: 200px;
    height: 200px;
    background: green;
    position:absolute;
    left:0;
    top: 0;
    bottom: 0;
    right: 0;
    margin: auto;
}
           
  1. margin 負間距法(必須知道子級元素的寬高)
<div class="con">
	<div class="center">center</div>	
</div>
           
.con{
	width: 400px;
	height: 400px;
	position: relative;
	background-color: blue;
}
.center{
    width:200px;
    height: 200px;
    background:red;
    position: absolute;
    left:50%;
    top:50%;
    margin-left:-100px;
    margin-top:-100px;
}
           
  1. CSS3的transform方法
<div class="con">
	<div class="center">center</div>	
</div>
           
.con{
	width: 400px;
	height: 400px;
	position: relative;
	background-color: blue;
}
.center{
    width: 200px;
    height: 200px;
    background: green;
    position:absolute;
    left:50%;    /* 定位父級的50% */
    top:50%;
    transform: translate(-50%,-50%); /*自己的50% */
}
           
  1. Flex布局
父元素flex布局,使用justify-content和align-items:center使子元素居中
<div class="con">
	<div class="center">center</div>	
</div>
           
.con{
	width: 400px;
	height: 400px;
	display:flex;
	justify-content:center;//水準方向
	align-items:center;//垂直方向
	background-color: red;
}
.center{
    width: 200px;
    height: 200px;
    background: green;
}
           

BFC

首先要知道什麼是BFC?

BFC:塊級格式化上下文

如何建立BFC?

(1)float屬性不為none(浮動)

(2)position為absolute或fixed(position絕對定位)

(3)display為 table, inline-block, table-cell, table-caption, flex, inline-flex(display:table-cell)

(4)overflow不為visible (overflow:hidden,overflow:auto)

BFC渲染規則?

(1)BFC垂直方向上的邊距會發生重疊

(2)BFC不會和浮動元素重疊(清除浮動)

(3)Bfc在頁面上是一個獨立的容器,外面的元素不會影響内部元素,内部的元素不會影響外部元素

(4)計算bfc高度的時候,浮動元素也會參與計算

BFC能夠做什麼?

(1)利用BFC避免外邊距折疊,若兩個相鄰元素在不同的BFC中,就能避免外邊距折疊。

(2)BFC包含浮動,解決容器高度不會被撐開的問題。同時也清除浮動!

(3)多欄布局的一種方式。

浮動

為什麼要浮動?

将多個塊級元素放到一行顯示

為什麼要清除浮動?

清除浮動是為了清除使用浮動帶來的影響,因為浮動的元素被排除到文檔流之外,其餘元素會補位,造成高度塌陷,頁面布局不能正常顯示。

清除浮動的方法?

  1. 在結尾處添加空div标簽clear:both
<div class="div1"> 
	<div class="left">Left</div> 
	<div class="right">Right</div>
	<div class="clearfloat"></div>
</div>
<div class="div2">div2</div>
           
.div1{background:#000080;border:1px solid red}
   .div2{background:#800080;border:1px solid red;height:100px;margin-top:10px}
   .left{float:left;width:20%;height:200px;background:#DDD}
   .right{float:right;width:30%;height:80px;background:#DDD}
   
   /*清除浮動代碼*/
   .clearfloat{clear:both}
           
缺點:添加無意義的空标簽,不利于後期維護,在實際開發中不會用到。
  1. 父級div定義overflow:hidden
<div class="div1"> 
	<div class="left">Left</div> 
	<div class="right">Right</div>
</div>
<div class="div2">div2</div>
           
.div1{background:#000080;border:1px solid red;/*解決代碼*/width:98%;overflow:hidden}
   .div2{background:#800080;border:1px solid red;height:100px;margin-top:10px;width:98%}
   
   .left{float:left;width:20%;height:200px;background:#DDD}
   .right{float:right;width:30%;height:80px;background:#DDD}
           
必須定義width或zoom:1
  1. 父級元素也設定浮動
缺點:使得與父元素相鄰的元素布局會受到影響,不可能一直浮動到body,隻做了解,不推薦使用。
  1. 使用:after僞元素(實際開發中最常用的方法)
clearfix是父元素的一個類名。
.clearfix:after{
		content:'';
		display:block;
		height:0;
		clear:both;
	}
	.clearfix{
		zoom:1/*為了相容ie6*/
	}
           

CSS盒模型

兩種盒子模型:标準盒子模型和IE盒子模型,在CSS3中新增了一個box-sizing屬性,這個屬性和盒子模型有關。box-sizing:content-box(預設)時,是标準盒子模型,box-sizing:border-box時,是IE盒子模型。
前端面試技巧頁面布局CSS盒模型DOM事件HTTP協定類原型鍊面向對象通信類浏覽器渲染機制頁面性能安全類結語

标準盒子模型中,width值content部分的寬度。

前端面試技巧頁面布局CSS盒模型DOM事件HTTP協定類原型鍊面向對象通信類浏覽器渲染機制頁面性能安全類結語

而在IE盒子模型中,width指的是content+paddingh+border這三部分的寬度。這就是兩種盒子模型的不同之處。

DOM事件

DOM事件的級别?

DOM0:element.onclick=function(){}   //後面的click事件會覆寫前面的click事件
DOM2:element.addEventListener(‘click’,function(){},false)//false表示在冒泡階段調用事件處理程式,true表示在捕獲階段調用事件處理程式。允許給一個事件注冊多個監聽器,即後面的事件不會覆寫前面的事件。
DOM3:element.addEventListener(‘keyup’,function(){},false)//增加了事件類型,例如鍵盤事件
           

事件流?

第一階段:捕獲,第二階段:目标階段,第三階段:冒泡

事件冒泡?

自下而上的觸發事件。

事件委托?

利用冒泡原理,目标元素将自身的響應事件委托給其父級元素來響應。

事件委托經典例子,經常問到:點選li彈出,彈出li對應的索引值。

常見的做法:

<ul>
	<li>1</li>
	<li>2</li>
	<li>3</li>
</ul>
           
var oli = document.getElementsByTagName('li');
for (let i = 0; i < oli.length; i++) {
	oli[i].onclick = function(){
		alert(i);
	}
};
           
注意:這裡的for循環内定義的變量 i 不能用 var 定義,因為DOM事件是異步任務,是以此處如果使用var i = 0;那麼每次彈出的都是3,因為當點選事件觸發的時候,for循環已經執行完畢,i等于3。可以用let解決這個問題,因為let是塊級作用域。

也可以使用立即執行函數來實作類似的塊級作用域的效果。

var oli = document.getElementsByTagName('li');
for (var i = 0; i < oli.length; i++) {
	(function(i){
		oli[i].onclick = function(){
			alert(i);
		}
	})(i)
};
           

最好的方法:使用事件委托實作:

var oul = document.querySelector('ul');
var oli = document.getElementsByTagName('li');

oul.addEventListener('click',function(event){
	var ev = event||window.event;
	var target = ev.target;
	for (var i = 0; i < oli.length; i++) {
		if(oli[i]== target){
			alert(i)
		}
	};
	/*if (target.nodeName === 'LI') { //彈出li裡面的内容
		alert(target.innerHTML)
	};*/
})
           
事件委托的好處:(1)不用循環周遊所有的Li,然後為Li添加事件。(2)減少對DOM的通路而提高性能,監聽動态增加的元素(動态增加的元素不用重新綁定事件,事件委托給父級元素)

HTTP協定類

http協定的主要特點?

(1)簡單快速:想要通路某個資源,隻要輸入這個資源的uri(統一資源符)即可。

(2)靈活:每個http協定頭部分有一個資料類型,通過http協定可以完成不同類型的資料傳輸。

(3)無連接配接:伺服器處理完客戶的請求,并收到客戶的應答後,即斷開連接配接。 (連接配接一次就會斷掉)

(4)無狀态:HTTP協定不對請求和響應之間的通信狀态進行儲存。是以使用HTTP協定,每當有新的請求發送,就會有對應的新響應産生。

http封包?

(1)請求封包:輸入url位址,用戶端發送請求封包,包括:請求行(http方法,頁面位址,httpx協定及版本)、請求頭(key,value值,告訴服務端要哪些内容)、空行(分隔請求行和請求體)、請求體。

(2)響應封包:服務端接受到之後,做出響應,傳回響應封包,包括:狀态行(http協定及版本,狀态碼)、響應頭、空行、響應體。

http方法?

Get---->擷取資源

Post---->傳輸資源

Head—>獲得封包首部

Put—>更新資源

Delete—>删除資源

Post和get的差別:

(1)get在浏覽器回退時是無害的(不會重複送出),而post會再次送出請求

(2)Get參數通過url傳遞,post請求會把送出的資料放在http請求封包的請求體中

(3)post比get安全,因為get請求的參數直接暴露在url上,是以不能用來傳遞敏感資訊

(4)Get請求的長度受 浏覽器或伺服器對url長度的 限制,允許發送的資料量較小,而Post沒有大小限制。

http狀态碼:

1開頭,訓示資訊

2開頭,響應成功

3開頭,伺服器重定向響應

4開頭,用戶端錯誤

5開頭,服務端錯誤

常見http狀态碼:200,301,302,304,400,401,403,404,500,502,503,504

200 OK 正常傳回資訊。

301 Moved Permanently 永久重定向,請求的頁面已永久移動到新的位置。

302 Found 臨時性重定向。請求的頁面已經轉移至新的url。

304 Not Modified 自從上次請求後,請求的頁面未修改過,伺服器告訴用戶端浏覽器中有緩存,可以直接使用緩存。

400 Bad Request 用戶端有文法錯誤。

401 Unauthorized 請求未授權。

403 Forbidden 資源被禁止通路。

404 Not Found 請求的資源不存在。

500 最常見的伺服器端錯誤。

502 錯誤的網關。

503 伺服器過載或維護。

504 網關逾時。

原型鍊

建立對象有幾種方法?

//(1)對象字面量:
 var o1 ={
    Name:'xd'
}
//(2)
var o2 = new Object();
o2.name = 'xd';

//(3)
var p = {name:'xd'};
 var o3 = Object.create(P)//特點,03的原型對象就是p
           

原型對象,構造函數,執行個體之間的關系?

前端面試技巧頁面布局CSS盒模型DOM事件HTTP協定類原型鍊面向對象通信類浏覽器渲染機制頁面性能安全類結語

(1)每個構造函數都有一個prototype屬性,指向這個構造函數的原型對象。

(2)原型對象有一個constructor屬性,指向原型對象的構造函數。

(3)執行個體通過new一個構造函數建立,執行個體通過__proto__可以找到構造函數的原型對象。

(4)每個原型對象都有__proto__屬性,指向原型對象的上一級原型對象。

介紹一下原型鍊?

原型鍊:原型對象上的屬性和方法是被構造函數建立的執行個體所共有的,當通路一個執行個體的屬性或方法的時候,在這個執行個體上本身上沒有找到這個屬性或方法,往原型對象上找,(通過__proto__),如果在上一級原型對象上還沒找到這個屬性或方法,會在這個原型對象的基礎上,沿着__proto__繼續往上一級原型對象查找,依次類推,直到找到一個名字比對的屬性或方法或到達原型鍊的末尾:null。

擴充:介紹一下作用域鍊?

作用域:作用域的特點就是,先在自己的變量範圍中查找,如果找不到,就會沿着作用域往上找。
var a = 1;
function b(){ 
	var a = 2; 
	function c(){ 
		var a = 3;
		console.log(a); 
	} 
	c();
}
b();
           

最後列印出來的是3,因為執行函數c()的時候它在自己的範圍内找到了變量a是以就不會越上繼續查找,如果在函數c()中沒有找到則會繼續向上找,一直會找到全局變量a,這個查找的過程就叫作用域鍊。

面向對象

類的聲明

兩種方法:(1)通過構造函數模拟一個類(2)ES6中對類的聲明

function Animal1(){//類+構造函數
	this.name = 'name'
}
class Animal2 {//類
	constructor(){//構造函數
		this.name
	}
}
           

JS 繼承

繼承實作的原理?

通過原型鍊實作繼承

有幾種方法實作繼承?各自優缺點?

  1. 借用構造函數實作繼承
原理:通過在子類的構造函數裡面執行父類的構造函數,父類構造函數裡的屬性和方法就都挂載到子類的執行個體上面了!
function Parent1(){
	this.name = "parent1"
}
Parent1.prototype.say = function(){}//原型對象上的方法并沒有辦法繼承的
function Child1(){
	Parent1.call(this);//在子類的構造函數裡面執行父級的構造函數
	this.type = 'child1';
}
console.log(new Child1,new Parent1())//沒有參數()可以省略
           
缺點:實作部分繼承!父類原型鍊上的屬性和方法并沒有被子類所繼承,子類繼承的隻是父類構造函數裡面的屬性和方法。
  1. 原型鍊繼承
原理:将父類的執行個體指派給子類的原型對象。
function Parent2(){
	this.name = 'parent2';
	this.play = [1,2,3]
}
function Child2(){
	this.type = 'child2'
}
Child2.prototype = new Parent2();//将父類的執行個體賦給子類的原型對象,這樣本來存在于父類執行個體中的所有屬性和方法,也都存在于子類的原型對象上了。

//存在的問題:
var s1 = new Child2();
var s2 = new Child2();
console.log(s1.play,s2.play)// [1, 2, 3] , [1, 2, 3]
s1.play.push(4);
console.log(s1.play,s2.play)// [1, 2, 3, 4] ,[1, 2, 3, 4]
           
缺點:問題主要在包含引用值的原型上,一個執行個體改變會導緻原型上内容的改變。
  1. 組合繼承(僞經典繼承,實際開發中最常用的方法)
原理:是将原型鍊和借用構造函數組合到一起的一種繼承模式,主要思路就是使用原型鍊實作對原型屬性和方法的繼承,而通過借用構造函數來實作對執行個體屬性的繼承。
function Parent3(){
	this.name = 'parent3'
	this.play = [1,2,3]
}
function Child3(){
	Parent3.call(this);
	this.type='child3'
}
Child3.prototype = new Parent3();//此處是為了解決“借用構造函數繼承”存在的缺點,即繼承父類原型對象上的屬性和方法。
var s3 = new Child3();
var s4 = new Child3();
s3.play.push(3);
console.log(s3.play,s4.play)// [1, 2, 3, 3],[1, 2, 3]
           
缺點:可以看出在這個過程中父類的構造函數使用了兩次,一次在建立子類原型的時候,另一次是在子類構造函數内部,但是使用過程中,子類的執行個體屬性會屏蔽原型屬性,也就是說某些原型屬性其實是用不上的,這造成了記憶體的浪費。
  1. 組合模式的優化

借用構造函數存在缺點:實作部分繼承!父類原型鍊上的屬性和方法并沒有被子類所繼承,子類繼承的隻是父類構造函數裡面的屬性和方法。

優化方法實作将構造函數的屬性和方法拿到,父類原型鍊上的屬性和方法也可以拿到,這樣父類隻執行了一次。

function Parent4(){
	this.name = 'parent4'
	this.play = [1,2,3]
}
function Child4(){
	Parent4.call(this);
	this.type='child4'
}
Child4.prototype = Parent4.prototype;//子類和父類的原型對象是同一個(公用原型對象)
var s5 = new Child4();
var s6 = new Child4();
s5.play.push(3);
console.log(s5.play,s6.play)//(4) [1, 2, 3, 3] (3) [1, 2, 3]
           
缺點:無法判斷執行個體到底是哪個構造函數生成的
  1. 經典繼承(最優方法,但是實際開發中用的并不多)

第一步常見父類類原型的一個副本。

第二步為建立的副本添加constructer屬性,彌補一下因為重寫原型而失去的預設的constructer屬性,

第三步将新建立的對象賦給子類的原型。

function Parent5(){
	this.name = 'parent5'
	this.play = [1,2,3]
}
function Child5(){
	Parent5.call(this);
	this.type='child5'
}
var obj1 = Object.create(Parent5.prototype);//Object.create建立的對象的特點:建立對象的原型對象就是括号裡的參數!
obj1.constructor = Child5;
Child5.prototype = obj1;
var s7 = new Child5();
console.log(s7)
console.log(s7 instanceof Child5,s7 instanceof Parent5)
console.log(s7.constructor === Child5)
           

注意:繼承這部分更詳細的介紹參考《JavaScript進階程式設計》(第三版),這本書裡有更加詳細的介紹,作為面試考點,不會要求書裡寫的那幾種方法從頭到尾全部介紹一遍,可能會挑出一個最常用的方法,比如:組合繼承是怎麼實作的?最多再問一個如何經典繼承?原型鍊和繼承是JS裡面較難懂的部分,需要慢慢了解。

通信類

同源政策及限制

什麼是同源政策?

所謂“同源”指的是三個相同。
  • 協定相同
  • 域名相同
  • 端口相同

舉例來說,http://www.example.com/dir/page.html 這個網址,協定是http://,域名是www.example.com,端口是80(預設端口可以省略)。它的同源情況如下。

前端面試技巧頁面布局CSS盒模型DOM事件HTTP協定類原型鍊面向對象通信類浏覽器渲染機制頁面性能安全類結語

同源政策的目的?

保證使用者資訊的安全,防止惡意的網站竊取資料。

限制範圍?

目前,如果非同源,共有三種行為受到限制。

(1) Cookie、LocalStorage 和 IndexDB 無法讀取。

(2) DOM 無法獲得。

(3) AJAX 請求不能發送。(Ajax隻适合同源的通信)

前後端通信的方式

常用方式:Ajax、WebSocket、CORS

什麼是Ajax?

異步的javascript和xml AJAX 是一種用于建立快速動态網頁的技術。 ajax用來與背景互動。

WebSocket是一種通信協定,使用ws://(非加密)和wss://(加密)作為協定字首。該協定不實行同源政策,隻要伺服器支援,就可以通過它進行跨源通信。

CORS是跨源資源分享(Cross-Origin Resource Sharing)的縮寫。它是W3C标準,是跨源AJAX請求的根本解決方法。相比JSONP隻能發GET請求,CORS允許任何類型的請求。

如何用原生JS建立Ajax?

window.onload = function(){
        //第一步:建立XMLHttpRequest對象
        //xhr是一個對象;裡面可以放很多東西,資料;
        var xhr = null;
        if(window.XMLHttpRequest){//标準浏覽器,判斷XMLHttpRequest對象是否存在
            xhr = new XMLHttpRequest();//建立一個對象
        }else{//早期的IE浏覽器,相容性
            xhr = new ActiveXObject('Microsoft.XMLHTTP');//參數是規定的;
        }
        console.log("狀态q"+xhr.readyState);//0
        //第二步:準備發送請求-配置發送請求的一些行為,确定XMLHttpRequest對象的發送方式,是http的哪個協定,是get\post\delete等
        //open即打開連結,第一個參數是以什麼方式;第二個是往哪兒發送請求,第三個可以不寫,預設true,表示異步,false表示同步;;
        xhr.open('get','03form.php',true);
        console.log("狀态w"+xhr.readyState);//1

        //第三步:執行發送的動作
        //send也可以寫在前面,推薦寫在後面;寫null是相容問題;
        xhr.send(null);
        console.log("狀态e"+xhr.readyState);//1

        //第四步:指定一些回調函數,也屬于事件函數;不觸發不執行,觸發條件是xhr.readyState;z這個值有0-4,共5個狀态,是由浏覽器控制的;
        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4){//4指伺服器傳回的資料可以使用;
                if(xhr.status == 200){ //判斷已經成功的擷取了資料;200表示hTTP請求成功;404表示找不到頁面;503表示伺服器端有文法錯誤;
                    var data = xhr.responseText;//json,文本,主角;
                    // var data1 = xhr.responseXML;
                }
            }
            // console.log("狀态t"+xhr.readyState);//2表示已經發送完成;

            // console.log(1234);
        }

        // console.log(456);
        console.log("狀态r"+xhr.readyState);//1


    }
           

簡化版,說出關鍵步驟即可。

//步驟一:建立XMLHttpRequest對象
var ajax = new XMLHttpRequest();
//步驟二:用open确定XMLHttpRequest對象的發送方式put\get\post\delete
ajax.open('get','getStar.php?starName='+name);
//步驟三:發送請求
ajax.send();
//步驟四:注冊事件 onreadystatechange 狀态改變就會調用
ajax.onreadystatechange = function () {
   if (ajax.readyState==4 &&(ajax.status==200||ajax.status ==304)) {//readyState=4,說明請求完成。後面的ajax.status是判斷http的狀态碼,200一切正常,304表示重定向,利用本地緩存即可。
    //步驟五 如果能夠進到這個判斷 說明 資料 完美的回來了,并且請求的頁面是存在的
    console.log(ajax.responseText);//輸入相應的内容
    }
}
           

跨域

為什麼要跨域?

同源政策的目标就是限制跨域通信,但實際業務中又需要跨域通信。

實作跨域的方法?

最少說出JSONP、CORS、postMessage,其他的方法例如hash、WebSocket了解即可。
  1. JSONP
原理:利用Script标簽的異步加載來實作。

JSONP是伺服器與用戶端跨源通信的常用方法。最大特點就是簡單适用,老式浏覽器全部支援,伺服器改造非常小。它的基本思想是,網頁通過添加一個

<script>

元素,向伺服器請求JSON資料,這種做法不受同源政策限制;伺服器收到請求後,将資料放在一個指定名字的回調函數裡傳回來。

function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
}
function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};
           

上面代碼通過動态添加

<script>

元素,向伺服器example.com送出請求。注意,該請求的查詢字元串有一個callback參數,用來指定回調函數的名字,這對于JSONP是必需的。ip是向背景請求的資料!

伺服器收到這個請求以後,會将資料放在回調函數的參數位置傳回。

foo({
  "ip": "8.8.8.8"
});
           
jQuery實作JSONP:指定’dataType:jsonp’即可,預設success作為回調函數。
  1. CORS(Ajax的變種)
對于開發者來說,CORS通信與同源的AJAX通信沒有差别,代碼完全一樣。浏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭資訊,有時還會多出一次附加的請求,但使用者不會有感覺。

浏覽器将CORS請求分成兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)。

對于簡單請求,浏覽器直接發出CORS請求。具體來說,就是在頭資訊之中,增加一個Origin字段。 簡單請求的請求方法:post,get,head.

非簡單請求是那種對伺服器有特殊要求的請求,比如請求方法是PUT或DELETE非簡單請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。浏覽器先詢問伺服器,目前網頁所在的域名是否在伺服器的許可名單之中,以及可以使用哪些HTTP動詞和頭資訊字段。隻有得到肯定答複,浏覽器才會發出正式的XMLHttpRequest請求,否則就報錯。

CORS與JSONP的使用目的相同,但是比JSONP更強大。

JSONP隻支援GET請求,CORS支援所有類型的HTTP請求。JSONP的優勢在于支援老式浏覽器,以及可以向不支援CORS的網站請求資料。

  1. PostMessage(H5中新增的标準)

使用 postMessage 方法和 onmessage 事件來實作不同域之間的通信。

場景:目前頁面A通過iframe或frame嵌入了跨域的頁面B,A要給B發送消息。

舉例:在父架構頁面index.html發送obj對象給遠端伺服器的 wozien.com/test/b.html ,該頁面是通過iframe加載的,如下:

/******************父視窗********************/
//父視窗給子視窗發消息, mes是要發送的資訊
document.getElementByID('iframe').contentWindow.postMessage(msg,'子視窗源');
//document.getElementByID('iframe').contentWindow表示子視窗下的window對象

//監聽子視窗資訊
window.addEventListener('message',function(event){ ... });
 
/******************子視窗********************/
//監聽父視窗資訊 ,event.data接收父視窗傳來的資料(mes)
window.addEventListener('message',function(event){ console.log(event.data) })
//Onmessage事件,與onclick、onkeyup是一樣的!

//子視窗給父視窗發消息 
window.top.postMessage(msg,'父視窗源');
           

父視窗給子視窗發資訊,需要用iframe的contentWindow屬性作為調用主體。

子視窗給父視窗發的資訊需要使用window.top。

浏覽器渲染機制

浏覽器渲染過程

  1. 解析HTML生成DOM樹。
  2. 解析CSS生成CSS規則樹。
  3. 将DOM樹與CSS規則樹合并在一起生成渲染樹。
  4. 布局render樹,确定dom元素在頁面的位置大小等資訊。
  5. 繪制render樹,渲染到頁面顯示。

重繪和重排

重排(回流):當render tree中的一部分(或全部)因為元素的規模尺寸,布局,隐藏等改變而需要重新建構。這就稱為回流(reflow)。每個頁面至少需要一次回流,就是在頁面第一次加載的時候。在回流的時候,浏覽器會使渲染樹中受到影響的部分失效,并重新構造這部分渲染樹,完成回流後,浏覽器會重新繪制受影響的部分到螢幕中,該過程成為重繪。

重繪: 當render tree中的一些元素需要更新屬性,而這些屬性隻是影響元素的外觀,風格,而不會影響布局的,比如background-color。則就叫稱為重繪。

注意:重排必将引起重繪,而重繪不一定會引起重排。

重排觸發條件?

(1)添加或者删除可見的DOM元素;

(2)DOM元素位置改變;

(3)元素尺寸改變——邊距、填充、邊框、寬度和高度

(4)内容改變——比如文本改變或者圖檔大小改變而引起的計算值寬度和高度改變;

(5)頁面渲染初始化;(每個頁面至少需要一次重排,就是在頁面第一次加載的時候。)

(6)浏覽器視窗尺寸改變

重繪觸發條件?

改變元素外觀屬性。如:color,background-color等。

減少重繪的方法?

避免循環操作DOM。建立一個documentFragment或div,在它上面應用所有DOM操作,最後再把它添加到window.document。

1.将多次改變樣式的操作合并成一次。

2.将需要多次重排的元素,絕對定位(position屬性設為absolute或fixed),這樣此元素就脫離了文檔流,它的變化不會影響到其他元素。

浏覽器輸入URL後發生了什麼?

這是一道經典的面試題,由于此部分涉及的内容過多,這裡就不展開描述了,建議找一篇部落格再細看一下。如果面試的時候實在想不起具體内容,最起碼以下八點要點還是要說出來的。

1.DNS域名解析;

2.建立TCP連接配接;

3.發送HTTP請求;

4.伺服器處理請求;

5.傳回響應結果;

6.關閉TCP連接配接;

7.浏覽器解析HTML;

8.浏覽器布局渲染;

頁面性能

提升頁面性能的方法?

1、 資源壓縮合并,減少http請求。

2、非核心代碼異步加載->異步加載的方式->異步加載的差別

異步加載的方式(1)動态腳本加載(2)defer(3)async

動态腳本加載?

document.createElement(`'<script>'`);然後将建立的标簽加到body或head上:
document.body.appendChild()
document.getElementsByTagName("head")[0].appendChild()	
           

異步加載的差別?

(1)defer是在HTML解析之後才會執行,如果是多個,按照加載的順序依次執行(2)async是在加載完之後立即執行,如果是多個,執行順序和加載順序無關!

3、利用浏覽器緩存->緩存的分類->緩存的原理

浏覽器緩存:資源檔案在浏覽器中存在的備份,或者成為副本。例如網頁上的圖檔請求回來,把圖檔緩存到本地,存到電腦磁盤上,下次再通路的時候,從磁盤直接讀,而不再請求圖檔位址。

緩存分類?

(1)強緩存,在過期時間之前,不請求伺服器,直接從浏覽器副本拿過來用。http協定頭:在請求一個檔案的時候,響應頭上回顯示expires(過期值)伺服器的絕對時間,cache-contol:cache-control:max-age=3600用戶端相對時間。

(2)協商緩存,與協商緩存有關的http協定頭:

Last-modified(最後修改時間) 和if-modified-since,Etag和 if-none-match。

If-Modified-Since和 Last-Modified 一樣都是用于記錄頁面最後修改時間的 HTTP 頭資訊,隻是 Last-Modified 是由伺服器往用戶端發送的 HTTP 頭,而 If-Modified-Since 則是由用戶端往伺服器發送的頭,可 以看到,再次請求本地存在的 cache 頁面時,用戶端會通過 If-Modified-Since 頭将先前伺服器端發過來的 Last-Modified 最後修改時間戳發送給伺服器,這是為了讓伺服器端進行驗證,通過這個時間戳判斷用戶端的頁面是否是最新的,如果不是最新的,則傳回新的内容,如果是最新的,則 傳回 304 告訴用戶端其本地 緩存cache 的頁面是最新的,于是用戶端就可以直接從本地加載頁面了,這樣在網絡上傳輸的資料就會大大減少,同時也減輕了伺服器的負擔。

浏覽器發現本地有這個副本,但是浏覽器不确定用不用這個備份,需要向伺服器咨詢,要不要用副本。

ETags和If-None-Match的工作原理是在HTTP Response中添加ETags資訊。當用戶端再次請求該資源時,将在HTTP Request中加入If-None-Match資訊(ETags的值)。如果伺服器驗證資源的ETags沒有改變(該資源沒有改變),将傳回一個304狀态;否則,伺服器将傳回200狀态,并傳回該資源和新的ETags。

4、使用CDN

網站上靜态資源即css、js全都使用cdn分發,圖檔亦然,因為cdn擁有衆多伺服器,使用者請求可以請求距離他近的伺服器,加快速度。

5、請減少對DOM的操作:建立一個documentFragment或div,在它上面應用所有DOM操作,最後再把它添加到window.document。

6、CSS放在頁面最上面,JavaScript放在頁面最下面

浏覽器會在下載下傳完全部CSS之後對整個頁面進行渲染,是以最好的做法是将CSS(link)放在

<head></head>

裡面,讓浏覽器盡快下載下傳CSS。JS則相反,JS檔案過大有可能會阻塞整個頁面,造成頁面顯示緩慢,是以JS最好放在放在

<body></body>

之後。

安全類

前端安全涉及分類?

隻要能答出一下兩種即可:CSRF和XSS。

CSRF:中文名稱:跨站請求僞造。

攻擊原理:

CSRF攻擊是源于WEB的隐式身份驗證機制,WEB的身份驗證機制雖然可以保證一個請求是來自于某個使用者的浏覽器,但卻無法保證該請求是使用者準許發送的。跨站請求攻擊,簡單地說,是攻擊者通過一些技術手段欺騙使用者的浏覽器去通路一個自己曾經認證過的網站并以使用者的名義執行一些操作(如發郵件,發消息,甚至财産操作如轉賬和購買商品)。由于浏覽器曾經認證過,是以被通路的網站會認為是真正的使用者操作而去執行。這利用了web中使用者身份驗證的一個漏洞:簡單的身份驗證隻能保證請求發自某個使用者的浏覽器,卻不能保證請求本身是使用者自願發出的。(兩個因素:接口存在漏洞,使用者在網站上登入過)

防禦措施:加Token驗證、 HTTP Referer驗證、隐藏令牌

CSRF 攻擊之是以能夠成功,是因為黑客可以完全僞造使用者的請求,該請求中所有的使用者驗證資訊都是存在于 cookie 中,是以黑客可以在不知道這些驗證資訊的情況下直接利用使用者自己的 cookie 來通過安全驗證。要抵禦 CSRF,關鍵在于在請求中放入黑客所不能僞造的資訊,并且該資訊不存在于 cookie 之中。可以在 HTTP 請求中以參數的形式加入一個随機産生的 token,并在伺服器端建立一個攔截器來驗證這個 token,如果請求中沒有 token 或者 token 内容不正确,則認為可能是 CSRF 攻擊而拒絕該請求。

XSS:中文名稱:跨站腳本攻擊。

攻擊原理:

xss跨站腳本攻擊(Cross Site Scripting),是一種經常出現在web應用中的安全漏洞,指攻擊者在網頁中嵌入用戶端腳本(例如JavaScript), 當使用者浏覽此網頁時,腳本就會在使用者的浏覽器上執行,進而達到攻擊者的目的。比如擷取使用者的Cookie,導航到惡意網站,攜帶木馬等。

大部分的xss漏洞都是由于沒有處理好使用者的輸入,導緻攻擊腳本在浏覽器中執行,這就是跨站腳本漏洞的根源。

XSS分類:反射型、存儲型和DOM XSS

(1)反射型

反射型惡意代碼并沒有儲存在目标網站,大多數攻擊資料是包含在URL中,誘導使用者點選連結,觸發 XSS 代碼,達到劫持通路、擷取 cookies 的目的。

(2)存儲型(持久型)

通常是因為伺服器端将使用者輸入的惡意腳本沒有經過驗證就存儲在資料庫中,并且通過調用資料庫的方式,将資料呈現在浏覽器上,每當使用者打開浏覽器,惡意腳本就會執行。存儲型的 XSS 攻擊相比反射型的危害性更大,因為每當使用者打開頁面,惡意腳本都會執行。

(3)DOM XSS

DOM XSS攻擊不同于反射型XSS和存儲型XSS,DOM XSS代碼不需要伺服器端的解析,而是通過浏覽器端的DOM解析。這完全是用戶端的事情。

XSS 漏洞修複

原則: 不相信客戶輸入的資料

(1)将重要的cookie标記為http only, 這樣的話Javascript 中的document.cookie語句就不能擷取到cookie了.

(2)隻允許使用者輸入我們期望的資料。 例如: 年齡的textbox中,隻允許使用者輸入數字。 而數字之外的字元都過濾掉。

對資料進行Html Encode 處理

(3)過濾或移除特殊的Html标簽, 例如:

<script>, <iframe>

, < for <, > for >, &quot for

(4)過濾JavaScript 事件的标簽。例如 “οnclick=”, “onfocus” 等等。

(5)DOM XSS的發生主要是在JS中使用eval造成的,是以應當避免使用eval語句。

XSS和CSRF差別?

CSRF攻擊的前提是使用者通路一個已經認證過的網站,XSS是攻擊者在頁面内嵌攻擊腳本實作的。

結語

根據秋招面試經驗,以上問題經常被問到,在此特寫下這篇部落格,希望給找工作的小夥伴一點參考。最後,祝好!