總結了17年初到18年初百場前端面試的面試經驗(含答案)

yuxiaoliang發表於2018-07-10

我是一名剛畢業的程式媛,面試的崗位是前端開發工程師,從17年初找實習開始,先後面試了50多家公司,加上123面,總共經歷了上百場面試,其中包括百度,騰訊,阿里,滴滴,網易,美團等等,也面了一些中小公司的社招。

總結一下面試遇到的問題,希望對大家助,本文很長很長很長(省略n個很長),但是看完的話,確實可以加深前端基礎知識的理解,原文連結可以跳轉(如果對您有幫助,請幫我點個star,定時更新):

同時我的部落格地址是:https://github.com/forthealllight/blog 會定時更新一些學習心得,也歡迎star和fork

? 文章列表

一、基礎javascript篇

1. get請求傳參長度的誤區

誤區:我們經常說get請求引數的大小存在限制,而post請求的引數大小是無限制的。

實際上HTTP 協議從未規定 GET/POST 的請求長度限制是多少。對get請求引數的限制是來源與瀏覽器或web伺服器,瀏覽器或web伺服器限制了url的長度。為了明確這個概念,我們必須再次強調下面幾點:

  • HTTP 協議 未規定 GET 和POST的長度限制
  • GET的最大長度顯示是因為 瀏覽器和 web伺服器限制了 URI的長度
  • 不同的瀏覽器和WEB伺服器,限制的最大長度不一樣
  • 要支援IE,則最大長度為2083byte,若只支援Chrome,則最大長度 8182byte

2. 補充get和post請求在快取方面的區別

post/get的請求區別,具體不再贅述。

補充補充一個get和post在快取方面的區別:

  • get請求類似於查詢的過程,使用者獲取資料,可以不用每次都與資料庫連線,所以可以使用快取。
  • post不同,post做的一般是修改和刪除的工作,所以必須與資料庫互動,所以不能使用快取。因此get請求適合於請求快取。

3. 閉包

一句話可以概括:閉包就是能夠讀取其他函式內部變數的函式,或者子函式在外呼叫,子函式所在的父函式的作用域不會被釋放。

4. 類的建立和繼承

(1)類的建立(es5):new一個function,在這個function的prototype裡面增加屬性和方法。

下面來建立一個Animal類:

// 定義一個動物類
function Animal (name) {
  // 屬性
  this.name = name || 'Animal';
  // 例項方法
  this.sleep = function(){
    console.log(this.name + '正在睡覺!');
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};
複製程式碼

這樣就生成了一個Animal類,實力化生成物件後,有方法和屬性。

(2)類的繼承——原型鏈繼承

--原型鏈繼承
function Cat(){ }
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true 
console.log(cat instanceof Cat); //true
複製程式碼
  • 介紹:在這裡我們可以看到new了一個空物件,這個空物件指向Animal並且Cat.prototype指向了這個空物件,這種就是基於原型鏈的繼承。
  • 特點:基於原型鏈,既是父類的例項,也是子類的例項
  • 缺點:無法實現多繼承

(3)構造繼承:使用父類的建構函式來增強子類例項,等於是複製父類的例項屬性給子類(沒用到原型)

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
複製程式碼
  • 特點:可以實現多繼承
  • 缺點:只能繼承父類例項的屬性和方法,不能繼承原型上的屬性和方法。

(4)例項繼承和拷貝繼承

例項繼承:為父類例項新增新特性,作為子類例項返回

拷貝繼承:拷貝父類元素上的屬性和方法

上述兩個實用性不強,不一一舉例。

(5)組合繼承:相當於構造繼承和原型鏈繼承的組合體。通過呼叫父類構造,繼承父類的屬性並保留傳參的優點,然後通過將父類例項作為子類原型,實現函式複用

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
複製程式碼
  • 特點:可以繼承例項屬性/方法,也可以繼承原型屬性/方法
  • 缺點:呼叫了兩次父類建構函式,生成了兩份例項

(6)寄生組合繼承:通過寄生方式,砍掉父類的例項屬性,這樣,在呼叫兩次父類的構造的時候,就不會初始化兩次例項方法/屬性

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
(function(){
  // 建立一個沒有例項方法的類
  var Super = function(){};
  Super.prototype = Animal.prototype;
  //將例項作為子類的原型
  Cat.prototype = new Super();
})();
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
複製程式碼
  • 較為推薦

5. 如何解決非同步回撥地獄

promise、generator、async/await

6. 說說前端中的事件流

HTML中與javascript互動是通過事件驅動來實現的,例如滑鼠點選事件onclick、頁面的滾動事件onscroll等等,可以向文件或者文件中的元素新增事件偵聽器來預訂事件。想要知道這些事件是在什麼時候進行呼叫的,就需要了解一下“事件流”的概念。

什麼是事件流:事件流描述的是從頁面中接收事件的順序,DOM2級事件流包括下面幾個階段。

  • 事件捕獲階段
  • 處於目標階段
  • 事件冒泡階段

addEventListeneraddEventListener 是DOM2 級事件新增的指定事件處理程式的操作,這個方法接收3個引數:要處理的事件名、作為事件處理程式的函式和一個布林值。最後這個布林值引數如果是true,表示在捕獲階段呼叫事件處理程式;如果是false,表示在冒泡階段呼叫事件處理程式。

IE只支援事件冒泡

7. 如何讓事件先冒泡後捕獲

在DOM標準事件模型中,是先捕獲後冒泡。但是如果要實現先冒泡後捕獲的效果,對於同一個事件,監聽捕獲和冒泡,分別對應相應的處理函式,監聽到捕獲事件,先暫緩執行,直到冒泡事件被捕獲後再執行捕獲之間。

8. 事件委託

  • 簡介:事件委託指的是,不在事件的發生地(直接dom)上設定監聽函式,而是在其父元素上設定監聽函式,通過事件冒泡,父元素可以監聽到子元素上事件的觸發,通過判斷事件發生元素DOM的型別,來做出不同的響應。

  • 舉例:最經典的就是ul和li標籤的事件監聽,比如我們在新增事件時候,採用事件委託機制,不會在li標籤上直接新增,而是在ul父元素上新增。

  • 好處:比較合適動態元素的繫結,新新增的子元素也會有監聽函式,也可以有事件觸發機制。

9. 圖片的懶載入和預載入

  • 預載入:提前載入圖片,當使用者需要檢視時可直接從本地快取中渲染。

  • 懶載入:懶載入的主要目的是作為伺服器前端的優化,減少請求數或延遲請求數。

兩種技術的本質:兩者的行為是相反的,一個是提前載入,一個是遲緩甚至不載入。 懶載入對伺服器前端有一定的緩解壓力作用,預載入則會增加伺服器前端壓力。

10. mouseover和mouseenter的區別

  • mouseover:當滑鼠移入元素或其子元素都會觸發事件,所以有一個重複觸發,冒泡的過程。對應的移除事件是mouseout

  • mouseenter:當滑鼠移除元素本身(不包含元素的子元素)會觸發事件,也就是不會冒泡,對應的移除事件是mouseleave

11. js的new操作符做了哪些事情

new 操作符新建了一個空物件,這個物件原型指向建構函式的prototype,執行建構函式後返回這個物件。

12.改變函式內部this指標的指向函式(bind,apply,call的區別)

  • 通過apply和call改變函式的this指向,他們兩個函式的第一個引數都是一樣的表示要改變指向的那個物件,第二個引數,apply是陣列,而call則是arg1,arg2...這種形式。

  • 通過bind改變this作用域會返回一個新的函式,這個函式不會馬上執行。

13. js的各種位置,比如clientHeight,scrollHeight,offsetHeight ,以及scrollTop, offsetTop,clientTop的區別?

  • clientHeight:表示的是可視區域的高度,不包含border和滾動條

  • offsetHeight:表示可視區域的高度,包含了border和滾動條

  • scrollHeight:表示了所有區域的高度,包含了因為滾動被隱藏的部分。

  • clientTop:表示邊框border的厚度,在未指定的情況下一般為0

  • scrollTop:滾動後被隱藏的高度,獲取物件相對於由offsetParent屬性指定的父座標(css定位的元素或body元素)距離頂端的高度。

14. js拖拽功能的實現

  • 首先是三個事件,分別是mousedown,mousemove,mouseup 當滑鼠點選按下的時候,需要一個tag標識此時已經按下,可以執行mousemove裡面的具體方法。

  • clientX,clientY標識的是滑鼠的座標,分別標識橫座標和縱座標,並且我們用offsetX和offsetY來表示元素的元素的初始座標,移動的舉例應該是:

    滑鼠移動時候的座標-滑鼠按下去時候的座標。

    也就是說定位資訊為:

    滑鼠移動時候的座標-滑鼠按下去時候的座標+元素初始情況下的offetLeft.

  • 還有一點也是原理性的東西,也就是拖拽的同時是絕對定位,我們改變的是絕對定位條件下的left 以及top等等值。

補充:也可以通過html5的拖放(Drag 和 drop)來實現

二、進階javascript篇

1.自己實現一個bind函式

原理:通過apply或者call方法來實現。

(1)初始版本

Function.prototype.bind=function(obj,arg){
  var arg=Array.prototype.slice.call(arguments,1);
  var context=this;
  return function(newArg){
    arg=arg.concat(Array.prototype.slice.call(newArg));
    return context.apply(obj,arg);
  }
}
複製程式碼

(2) 考慮到原型鏈

為什麼要考慮?因為在new 一個bind過生成的新函式的時候,必須的條件是要繼承原函式的原型

Function.prototype.bind=function(obj,arg){
  var arg=Array.prototype.slice.call(arguments,1);
  var context=this;
  var bound=function(newArg){
    arg=arg.concat(Array.prototype.slice.call(newArg));
    return context.apply(obj,arg);
  }
  var F=function(){}
  //這裡需要一個寄生組合繼承
  F.prototype=context.prototype;
  bound.prototype=new F();
  return bound;
}
複製程式碼

2.用setTimeout來實現setInterval

(1)用setTimeout()方法來模擬setInterval()與setInterval()之間的什麼區別?

首先來看setInterval的缺陷,使用setInterval()建立的定時器確保了定時器程式碼規則地插入佇列中。這個問題在於:如果定時器程式碼在程式碼再次新增到佇列之前還沒完成執行,結果就會導致定時器程式碼連續執行好幾次。而之間沒有間隔。不過幸運的是:javascript引擎足夠聰明,能夠避免這個問題。當且僅當沒有該定時器的如何程式碼例項時,才會將定時器程式碼新增到佇列中。這確保了定時器程式碼加入佇列中最小的時間間隔為指定時間。

這種重複定時器的規則有兩個問題:1.某些間隔會被跳過 2.多個定時器的程式碼執行時間可能會比預期小。

下面舉例子說明:

假設,某個onclick事件處理程式使用啦setInterval()來設定了一個200ms的重複定時器。如果事件處理程式花了300ms多一點的時間完成。

2018-07-10 11 36 43

這個例子中的第一個定時器是在205ms處新增到佇列中,但是要過300ms才能執行。在405ms又新增了一個副本。在一個間隔,605ms處,第一個定時器程式碼還在執行中,而且佇列中已經有了一個定時器例項,結果是605ms的定時器程式碼不會新增到佇列中。結果是在5ms處新增的定時器程式碼執行結束後,405處的程式碼立即執行。

function say(){
  //something
  setTimeout(say,200);
}
setTimeout(say,200)
複製程式碼

或者

setTimeout(function(){
   //do something
   setTimeout(arguments.callee,200);
},200);
複製程式碼

3.js怎麼控制一次載入一張圖片,載入完後再載入下一張

(1)方法1

<script type="text/javascript">
var obj=new Image();
obj.src="http://www.phpernote.com/uploadfiles/editor/201107240502201179.jpg";
obj.onload=function(){
alert('圖片的寬度為:'+obj.width+';圖片的高度為:'+obj.height);
document.getElementById("mypic").innnerHTML="<img src='"+this.src+"' />";
}
</script>
<div id="mypic">onloading……</div>
複製程式碼

(2)方法2

<script type="text/javascript">
var obj=new Image();
obj.src="http://www.phpernote.com/uploadfiles/editor/201107240502201179.jpg";
obj.onreadystatechange=function(){
if(this.readyState=="complete"){
alert('圖片的寬度為:'+obj.width+';圖片的高度為:'+obj.height);
document.getElementById("mypic").innnerHTML="<img src='"+this.src+"' />";
}
}
</script>
<div id="mypic">onloading……</div>
複製程式碼

3.程式碼的執行順序

setTimeout(function(){console.log(1)},0);
new Promise(function(resolve,reject){
   console.log(2);
   resolve();
}).then(function(){console.log(3)
}).then(function(){console.log(4)});

process.nextTick(function(){console.log(5)});

console.log(6);
//輸出2,6,5,3,4,1
複製程式碼

為什麼呢?具體請參考我的文章: 從promise、process.nextTick、setTimeout出發,談談Event Loop中的Job queue

4.如何實現sleep的效果(es5或者es6)

(1)while迴圈的方式

function sleep(ms){
   var start=Date.now(),expire=start+ms;
   while(Date.now()<expire);
   console.log('1111');
   return;
}
複製程式碼

執行sleep(1000)之後,休眠了1000ms之後輸出了1111。上述迴圈的方式缺點很明顯,容易造成死迴圈。

(2)通過promise來實現

function sleep(ms){
  var temple=new Promise(
  (resolve)=>{
  console.log(111);setTimeout(resolve,ms)
  });
  return temple
}
sleep(500).then(function(){
   //console.log(222)
})
//先輸出了111,延遲500ms後輸出222
複製程式碼

(3)通過async封裝

function sleep(ms){
  return new Promise((resolve)=>setTimeout(resolve,ms));
}
async function test(){
  var temple=await sleep(1000);
  console.log(1111)
  return temple
}
test();
//延遲1000ms輸出了1111
複製程式碼

####(4).通過generate來實現

function* sleep(ms){
   yield new Promise(function(resolve,reject){
             console.log(111);
             setTimeout(resolve,ms);
        })  
}
sleep(500).next().value.then(function(){console.log(2222)})
複製程式碼

5.簡單的實現一個promise

首先明確什麼是promiseA+規範,參考規範的地址:

primiseA+規範

如何實現一個promise,參考我的文章:

實現一個完美符合Promise/A+規範的Promise

一般不會問的很詳細,只要能寫出上述文章中的v1.0版本的簡單promise即可。

6.Function._proto_(getPrototypeOf)是什麼?

獲取一個物件的原型,在chrome中可以通過__proto__的形式,或者在ES6中可以通過Object.getPrototypeOf的形式。

那麼Function.proto是什麼麼?也就是說Function由什麼物件繼承而來,我們來做如下判別。

Function.__proto__==Object.prototype //false
Function.__proto__==Function.prototype//true
複製程式碼

我們發現Function的原型也是Function。

我們用圖可以來明確這個關係:

2018-07-10 2 38 27

7.實現js中所有物件的深度克隆(包裝物件,Date物件,正則物件)

通過遞迴可以簡單實現物件的深度克隆,但是這種方法不管是ES6還是ES5實現,都有同樣的缺陷,就是隻能實現特定的object的深度複製(比如陣列和函式),不能實現包裝物件Number,String , Boolean,以及Date物件,RegExp物件的複製。

(1)前文的方法

function deepClone(obj){
    var newObj= obj instanceof Array?[]:{};
    for(var i in obj){
       newObj[i]=typeof obj[i]=='object'?  
       deepClone(obj[i]):obj[i];    
    }
    return newObj;
}
複製程式碼

這種方法可以實現一般物件和陣列物件的克隆,比如:

var arr=[1,2,3];
var newArr=deepClone(arr);
// newArr->[1,2,3]

var obj={
   x:1,
   y:2
}
var newObj=deepClone(obj);
// newObj={x:1,y:2}
複製程式碼

但是不能實現例如包裝物件Number,String,Boolean,以及正則物件RegExp和Date物件的克隆,比如:

//Number包裝物件
var num=new Number(1);
typeof num // "object"

var newNum=deepClone(num);
//newNum ->  {} 空物件

//String包裝物件
var str=new String("hello");
typeof str //"object"

var newStr=deepClone(str);
//newStr->  {0:'h',1:'e',2:'l',3:'l',4:'o'};

//Boolean包裝物件
var bol=new Boolean(true);
typeof bol //"object"

var newBol=deepClone(bol);
// newBol ->{} 空物件

....
複製程式碼

(2)valueof()函式

所有物件都有valueOf方法,valueOf方法對於:如果存在任意原始值,它就預設將物件轉換為表示它的原始值。物件是複合值,而且大多數物件無法真正表示為一個原始值,因此預設的valueOf()方法簡單地返回物件本身,而不是返回一個原始值。陣列、函式和正規表示式簡單地繼承了這個預設方法,呼叫這些型別的例項的valueOf()方法只是簡單返回這個物件本身。

對於原始值或者包裝類:

function baseClone(base){
 return base.valueOf();
}

//Number
var num=new Number(1);
var newNum=baseClone(num);
//newNum->1

//String
var str=new String('hello');
var newStr=baseClone(str);
// newStr->"hello"

//Boolean
var bol=new Boolean(true);
var newBol=baseClone(bol);
//newBol-> true
複製程式碼

其實對於包裝類,完全可以用=號來進行克隆,其實沒有深度克隆一說,

這裡用valueOf實現,語法上比較符合規範。

對於Date型別:

因為valueOf方法,日期類定義的valueOf()方法會返回它的一個內部表示:1970年1月1日以來的毫秒數.因此我們可以在Date的原型上定義克隆的方法:

Date.prototype.clone=function(){
  return new Date(this.valueOf());
}

var date=new Date('2010');
var newDate=date.clone();
// newDate->  Fri Jan 01 2010 08:00:00 GMT+0800 
複製程式碼

對於正則物件RegExp:

RegExp.prototype.clone = function() {
var pattern = this.valueOf();
var flags = '';
flags += pattern.global ? 'g' : '';
flags += pattern.ignoreCase ? 'i' : '';
flags += pattern.multiline ? 'm' : '';
return new RegExp(pattern.source, flags);
};

var reg=new RegExp('/111/');
var newReg=reg.clone();
//newReg->  /\/111\//
複製程式碼

8.簡單實現Node的Events模組

簡介:觀察者模式或者說訂閱模式,它定義了物件間的一種一對多的關係,讓多個觀察者物件同時監聽某一個主題物件,當一個物件發生改變時,所有依賴於它的物件都將得到通知。

node中的Events模組就是通過觀察者模式來實現的:

var events=require('events');
var eventEmitter=new events.EventEmitter();
eventEmitter.on('say',function(name){
    console.log('Hello',name);
})
eventEmitter.emit('say','Jony yu');
複製程式碼

這樣,eventEmitter發出say事件,通過On接收,並且輸出結果,這就是一個訂閱模式的實現,下面我們來簡單的實現一個Events模組的EventEmitter。

(1)實現簡單的Event模組的emit和on方法

function Events(){
this.on=function(eventName,callBack){
  if(!this.handles){
    this.handles={};
  }
  if(!this.handles[eventName]){
    this.handles[eventName]=[];
  }
  this.handles[eventName].push(callBack);
}
this.emit=function(eventName,obj){
   if(this.handles[eventName]){
     for(var i=0;o<this.handles[eventName].length;i++){
       this.handles[eventName][i](obj);
     }
   }
}
return this;
}
複製程式碼

這樣我們就定義了Events,現在我們可以開始來呼叫:

 var events=new Events();
 events.on('say',function(name){
    console.log('Hello',nama)
 });
 events.emit('say','Jony yu');
 //結果就是通過emit呼叫之後,輸出了Jony yu
複製程式碼

(2)每個物件是獨立的

因為是通過new的方式,每次生成的物件都是不相同的,因此:

var event1=new Events();
var event2=new Events();
event1.on('say',function(){
    console.log('Jony event1');
});
event2.on('say',function(){
    console.log('Jony event2');
})
event1.emit('say');
event2.emit('say');
//event1、event2之間的事件監聽互相不影響
//輸出結果為'Jony event1' 'Jony event2'
複製程式碼

9.箭頭函式中this指向舉例

var a=11;
function test2(){
  this.a=22;
  let b=()=>{console.log(this.a)}
  b();
}
var x=new test2();
//輸出22
複製程式碼

定義時繫結。

三、http、html和瀏覽器篇

1.http和https

https的SSL加密是在傳輸層實現的。

(1)http和https的基本概念

http: 超文字傳輸協議,是網際網路上應用最為廣泛的一種網路協議,是一個客戶端和伺服器端請求和應答的標準(TCP),用於從WWW伺服器傳輸超文字到本地瀏覽器的傳輸協議,它可以使瀏覽器更加高效,使網路傳輸減少。

https: 是以安全為目標的HTTP通道,簡單講是HTTP的安全版,即HTTP下加入SSL層,HTTPS的安全基礎是SSL,因此加密的詳細內容就需要SSL。

https協議的主要作用是:建立一個資訊保安通道,來確保陣列的傳輸,確保網站的真實性。

(2)http和https的區別?

http傳輸的資料都是未加密的,也就是明文的,網景公司設定了SSL協議來對http協議傳輸的資料進行加密處理,簡單來說https協議是由http和ssl協議構建的可進行加密傳輸和身份認證的網路協議,比http協議的安全性更高。 主要的區別如下:

  • Https協議需要ca證照,費用較高。
  • http是超文字傳輸協議,資訊是明文傳輸,https則是具有安全性的ssl加密傳輸協議。
  • 使用不同的連結方式,埠也不同,一般而言,http協議的埠為80,https的埠為443
  • http的連線很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網路協議,比http協議安全。

(3)https協議的工作原理

客戶端在使用HTTPS方式與Web伺服器通訊時有以下幾個步驟,如圖所示。

  • 客戶使用https url訪問伺服器,則要求web 伺服器建立ssl連結。
  • web伺服器接收到客戶端的請求之後,會將網站的證照(證照中包含了公鑰),返回或者說傳輸給客戶端。
  • 客戶端和web伺服器端開始協商SSL連結的安全等級,也就是加密等級。
  • 客戶端瀏覽器通過雙方協商一致的安全等級,建立會話金鑰,然後通過網站的公鑰來加密會話金鑰,並傳送給網站。
  • web伺服器通過自己的私鑰解密出會話金鑰。
  • web伺服器通過會話金鑰加密與客戶端之間的通訊。

(4)https協議的優點

  • 使用HTTPS協議可認證使用者和伺服器,確保資料傳送到正確的客戶機和伺服器;
  • HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網路協議,要比http協議安全,可防止資料在傳輸過程中不被竊取、改變,確保資料的完整性。
  • HTTPS是現行架構下最安全的解決方案,雖然不是絕對安全,但它大幅增加了中間人攻擊的成本。
  • 谷歌曾在2014年8月份調整搜尋引擎演算法,並稱“比起同等HTTP網站,採用HTTPS加密的網站在搜尋結果中的排名將會更高”。

(5)https協議的缺點

  • https握手階段比較費時,會使頁面載入時間延長50%,增加10%~20%的耗電。
  • https快取不如http高效,會增加資料開銷。
  • SSL證照也需要錢,功能越強大的證照費用越高。
  • SSL證照需要繫結IP,不能再同一個ip上繫結多個域名,ipv4資源支援不了這種消耗。

2.tcp三次握手,一句話概括

客戶端和服務端都需要直到各自可收發,因此需要三次握手。

簡化三次握手:

2018-07-10 3 42 11

從圖片可以得到三次握手可以簡化為:C發起請求連線S確認,也發起連線C確認我們再看看每次握手的作用:第一次握手:S只可以確認 自己可以接受C傳送的報文段第二次握手:C可以確認 S收到了自己傳送的報文段,並且可以確認 自己可以接受S傳送的報文段第三次握手:S可以確認 C收到了自己傳送的報文段

3.TCP和UDP的區別

(1)TCP是面向連線的,udp是無連線的即傳送資料前不需要先建立連結。

(2)TCP提供可靠的服務。也就是說,通過TCP連線傳送的資料,無差錯,不丟失,不重複,且按序到達;UDP盡最大努力交付,即不保證可靠交付。 並且因為tcp可靠,面向連線,不會丟失資料因此適合大資料量的交換。

(3)TCP是面向位元組流,UDP面向報文,並且網路出現擁塞不會使得傳送速率降低(因此會出現丟包,對實時的應用比如IP電話和視訊會議等)。

(4)TCP只能是1對1的,UDP支援1對1,1對多。

(5)TCP的首部較大為20位元組,而UDP只有8位元組。

(6)TCP是面向連線的可靠性傳輸,而UDP是不可靠的。

4.WebSocket的實現和應用

(1)什麼是WebSocket?

WebSocket是HTML5中的協議,支援持久連續,http協議不支援永續性連線。Http1.0和HTTP1.1都不支援永續性的連結,HTTP1.1中的keep-alive,將多個http請求合併為1個

(2)WebSocket是什麼樣的協議,具體有什麼優點?

  • HTTP的生命週期通過Request來界定,也就是Request一個Response,那麼在Http1.0協議中,這次Http請求就結束了。在Http1.1中進行了改進,是的有一個connection:Keep-alive,也就是說,在一個Http連線中,可以傳送多個Request,接收多個Response。但是必須記住,在Http中一個Request只能對應有一個Response,而且這個Response是被動的,不能主動發起。
  • WebSocket是基於Http協議的,或者說借用了Http協議來完成一部分握手,在握手階段與Http是相同的。我們來看一個websocket握手協議的實現,基本是2個屬性,upgrade,connection。

基本請求如下:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
複製程式碼

多了下面2個屬性:

Upgrade:webSocket
Connection:Upgrade
告訴伺服器傳送的是websocket
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
複製程式碼

5.HTTP請求的方式,HEAD方式

  • head:類似於get請求,只不過返回的響應中沒有具體的內容,使用者獲取報頭
  • options:允許客戶端檢視伺服器的效能,比如說伺服器支援的請求方式等等。

6.一個圖片url訪問後直接下載怎樣實現?

請求的返回頭裡面,用於瀏覽器解析的重要引數就是OSS的API文件裡面的返回http頭,決定使用者下載行為的引數。

下載的情況下:

  1. x-oss-object-type:
         Normal
  2. x-oss-request-id:
         598D5ED34F29D01FE2925F41
  3. x-oss-storage-class:
         Standard
複製程式碼

7.web Quality (無障礙)

能夠被殘障人士使用的網站才能稱得上一個易用的(易訪問的)網站。 殘障人士指的是那些帶有殘疾或者身體不健康的使用者。

使用alt屬性:

<img src="person.jpg"  alt="this is a person"/>
複製程式碼

有時候瀏覽器會無法顯示影像。具體的原因有:

  • 使用者關閉了影像顯示
  • 瀏覽器是不支援圖形顯示的迷你瀏覽器
  • 瀏覽器是語音瀏覽器(供盲人和弱視人群使用) 如果您使用了 alt 屬性,那麼瀏覽器至少可以顯示或讀出有關影像的描述。

8.幾個很實用的BOM屬性物件方法?

什麼是Bom? Bom是瀏覽器物件。有哪些常用的Bom屬性呢?

(1)location物件

location.href-- 返回或設定當前文件的URL location.search -- 返回URL中的查詢字串部分。例如 http://www.dreamdu.com/dreamdu.php?id=5&name=dreamdu 返回包括(?)後面的內容?id=5&name=dreamdu location.hash -- 返回URL#後面的內容,如果沒有#,返回空 location.host -- 返回URL中的域名部分,例如www.dreamdu.com location.hostname -- 返回URL中的主域名部分,例如dreamdu.com location.pathname -- 返回URL的域名後的部分。例如 http://www.dreamdu.com/xhtml/ 返回/xhtml/ location.port -- 返回URL中的埠部分。例如 http://www.dreamdu.com:8080/xhtml/ 返回8080 location.protocol -- 返回URL中的協議部分。例如 http://www.dreamdu.com:8080/xhtml/ 返回(//)前面的內容http: location.assign -- 設定當前文件的URL location.replace() -- 設定當前文件的URL,並且在history物件的地址列表中移除這個URL location.replace(url); location.reload() -- 過載當前頁面

(2)history物件

history.go() -- 前進或後退指定的頁面數 history.go(num); history.back() -- 後退一頁 history.forward() -- 前進一頁

(3)Navigator物件

navigator.userAgent -- 返回使用者代理頭的字串表示(就是包括瀏覽器版本資訊等的字串) navigator.cookieEnabled -- 返回瀏覽器是否支援(啟用)cookie

9.HTML5 drag api

  • dragstart:事件主體是被拖放元素,在開始拖放被拖放元素時觸發,。
  • darg:事件主體是被拖放元素,在正在拖放被拖放元素時觸發。
  • dragenter:事件主體是目標元素,在被拖放元素進入某元素時觸發。
  • dragover:事件主體是目標元素,在被拖放在某元素內移動時觸發。
  • dragleave:事件主體是目標元素,在被拖放元素移出目標元素是觸發。
  • drop:事件主體是目標元素,在目標元素完全接受被拖放元素時觸發。
  • dragend:事件主體是被拖放元素,在整個拖放操作結束時觸發

10.http2.0

首先補充一下,http和https的區別,相比於http,https是基於ssl加密的http協議 簡要概括:http2.0是基於1999年釋出的http1.0之後的首次更新。

  • 提升訪問速度(可以對於,請求資源所需時間更少,訪問速度更快,相比http1.0)
  • 允許多路複用:多路複用允許同時通過單一的HTTP/2連線傳送多重請求-響應資訊。改善了:在http1.1中,瀏覽器客戶端在同一時間,針對同一域名下的請求有一定數量限制(連線數量),超過限制會被阻塞。
  • 二進位制分幀:HTTP2.0會將所有的傳輸資訊分割為更小的資訊或者幀,並對他們進行二進位制編碼
  • 首部壓縮
  • 伺服器端推送

11.補充400和401、403狀態碼

(1)400狀態碼:請求無效

產生原因:

  • 前端提交資料的欄位名稱和欄位型別與後臺的實體沒有保持一致
  • 前端提交到後臺的資料應該是json字串型別,但是前端沒有將物件JSON.stringify轉化成字串。

解決方法:

  • 對照欄位的名稱,保持一致性
  • 將obj物件通過JSON.stringify實現序列化

(2)401狀態碼:當前請求需要使用者驗證

(3)403狀態碼:伺服器已經得到請求,但是拒絕執行

12.fetch傳送2次請求的原因

fetch傳送post請求的時候,總是傳送2次,第一次狀態碼是204,第二次才成功?

原因很簡單,因為你用fetch的post請求的時候,導致fetch 第一次傳送了一個Options請求,詢問伺服器是否支援修改的請求頭,如果伺服器支援,則在第二次中傳送真正的請求。

13.Cookie、sessionStorage、localStorage的區別

共同點:都是儲存在瀏覽器端,並且是同源的

  • Cookie:cookie資料始終在同源的http請求中攜帶(即使不需要),即cookie在瀏覽器和伺服器間來回傳遞。而sessionStorage和localStorage不會自動把資料發給伺服器,僅在本地儲存。cookie資料還有路徑(path)的概念,可以限制cookie只屬於某個路徑下,儲存的大小很小隻有4K左右。 (key:可以在瀏覽器和伺服器端來回傳遞,儲存容量小,只有大約4K左右)

  • sessionStorage:僅在當前瀏覽器視窗關閉前有效,自然也就不可能持久保持,localStorage:始終有效,視窗或瀏覽器關閉也一直儲存,因此用作持久資料;cookie只在設定的cookie過期時間之前一直有效,即使視窗或瀏覽器關閉。(key:本身就是一個回話過程,關閉瀏覽器後消失,session為一個回話,當頁面不同即使是同一頁面開啟兩次,也被視為同一次回話)

  • localStorage:localStorage 在所有同源視窗中都是共享的;cookie也是在所有同源視窗中都是共享的。(key:同源視窗都會共享,並且不會失效,不管視窗或者瀏覽器關閉與否都會始終生效)

補充說明一下cookie的作用:

  • 儲存使用者登入狀態。例如將使用者id儲存於一個cookie內,這樣當使用者下次訪問該頁面時就不需要重新登入了,現在很多論壇和社群都提供這樣的功能。 cookie還可以設定過期時間,當超過時間期限後,cookie就會自動消失。因此,系統往往可以提示使用者保持登入狀態的時間:常見選項有一個月、三個 月、一年等。

  • 跟蹤使用者行為。例如一個天氣預報網站,能夠根據使用者選擇的地區顯示當地的天氣情況。如果每次都需要選擇所在地是煩瑣的,當利用了 cookie後就會顯得很人性化了,系統能夠記住上一次訪問的地區,當下次再開啟該頁面時,它就會自動顯示上次使用者所在地區的天氣情況。因為一切都是在後 臺完成,所以這樣的頁面就像為某個使用者所定製的一樣,使用起來非常方便

  • 定製頁面。如果網站提供了換膚或更換佈局的功能,那麼可以使用cookie來記錄使用者的選項,例如:背景色、解析度等。當使用者下次訪問時,仍然可以儲存上一次訪問的介面風格。

14.web worker

在HTML頁面中,如果在執行指令碼時,頁面的狀態是不可相應的,直到指令碼執行完成後,頁面才變成可相應。web worker是執行在後臺的js,獨立於其他指令碼,不會影響頁面你的效能。並且通過postMessage將結果回傳到主執行緒。這樣在進行復雜操作的時候,就不會阻塞主執行緒了。

如何建立web worker:

  • 檢測瀏覽器對於web worker的支援性
  • 建立web worker檔案(js,回傳函式等)
  • 建立web worker物件

15.對HTML語義化標籤的理解

HTML5語義化標籤是指正確的標籤包含了正確的內容,結構良好,便於閱讀,比如nav表示導航條,類似的還有article、header、footer等等標籤。

16.iframe是什麼?有什麼缺點?

定義:iframe元素會建立包含另一個文件的內聯框架 提示:可以將提示文字放在之間,來提示某些不支援iframe的瀏覽器

缺點:

  • 會阻塞主頁面的onload事件
  • 搜尋引擎無法解讀這種頁面,不利於SEO
  • iframe和主頁面共享連線池,而瀏覽器對相同區域有限制所以會影響效能。

17.Doctype作用? 嚴格模式與混雜模式如何區分?它們有何意義?

Doctype宣告於文件最前面,告訴瀏覽器以何種方式來渲染頁面,這裡有兩種模式,嚴格模式和混雜模式。

  • 嚴格模式的排版和 JS 運作模式是 以該瀏覽器支援的最高標準執行。
  • 混雜模式,向後相容,模擬老式瀏覽器,防止瀏覽器無法相容頁面。

18.Cookie如何防範XSS攻擊

XSS(跨站指令碼攻擊)是指攻擊者在返回的HTML中嵌入javascript指令碼,為了減輕這些攻擊,需要在HTTP頭部配上,set-cookie:

  • httponly-這個屬性可以防止XSS,它會禁止javascript指令碼來訪問cookie。
  • secure - 這個屬性告訴瀏覽器僅在請求為https的時候傳送cookie。

結果應該是這樣的:Set-Cookie=.....

19.Cookie和session的區別

HTTP是一個無狀態協議,因此Cookie的最大的作用就是儲存sessionId用來唯一標識使用者

20. 一句話概括RESTFUL

就是用URL定位資源,用HTTP描述操作

21.講講viewport和移動端佈局

可以參考我的這篇文章:

響應式佈局的常用解決方案對比(媒體查詢、百分比、rem和vw/vh)

22. click在ios上有300ms延遲,原因及如何解決?

(1)粗暴型,禁用縮放

 <meta name="viewport" content="width=device-width, user-scalable=no"> 
複製程式碼

(2)利用FastClick,其原理是:

檢測到touchend事件後,立刻出發模擬click事件,並且把瀏覽器300毫秒之後真正出發的事件給阻斷掉

四、css篇

1.css盒模型

簡介:就是用來裝頁面上的元素的矩形區域。CSS中的盒子模型包括IE盒子模型和標準的W3C盒子模型。

border-sizing(有3個值哦):border-box,padding-box,content-box.

  • 標準盒子模型:
2018-07-10 4 24 03
  • IE盒子模型:
2018-07-10 4 24 12

區別:從圖中我們可以看出,這兩種盒子模型最主要的區別就是width的包含範圍,在標準的盒子模型中,width指content部分的寬度,在IE盒子模型中,width表示content+padding+border這三個部分的寬度,故這使得在計算整個盒子的寬度時存在著差異:

標準盒子模型的盒子寬度:左右border+左右padding+width IE盒子模型的盒子寬度:width

在CSS3中引入了box-sizing屬性,box-sizing:content-box;表示標準的盒子模型,box-sizing:border-box表示的是IE盒子模型

最後,前面我們還提到了,box-sizing:padding-box,這個屬性值的寬度包含了左右padding+width

也很好理解性記憶,包含什麼,width就從什麼開始算起。

2.畫一條0.5px的線

  • 採用meta viewport的方式

  • 採用 border-image的方式

  • 採用transform: scale()的方式

3.link標籤和import標籤的區別

  • link屬於html標籤,而@import是css提供的
  • 頁面被載入時,link會同時被載入,而@import引用的css會等到頁面載入結束後載入。
  • link是html標籤,因此沒有相容性,而@import只有IE5以上才能識別。
  • link方式樣式的權重高於@import的。

4.transition和animation的區別

Animation和transition大部分屬性是相同的,他們都是隨時間改變元素的屬性值,他們的主要區別是transition需要觸發一個事件才能改變屬性,而animation不需要觸發任何事件的情況下才會隨時間改變屬性值,並且transition為2幀,從from .... to,而animation可以一幀一幀的。

5.Flex佈局

文章連結: http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html?utm_source=tuicool(語法篇) http://www.ruanyifeng.com/blog/2015/07/flex-examples.html(例項篇)

Flex是Flexible Box的縮寫,意為"彈性佈局",用來為盒狀模型提供最大的靈活性。 佈局的傳統解決方案,基於盒狀模型,依賴 display屬性 + position屬性 + float屬性。它對於那些特殊佈局非常不方便,比如,垂直居中就不容易實現。

簡單的分為容器屬性和元素屬性 容器的屬性:

  • flex-direction:決定主軸的方向(即子item的排列方法) .box { flex-direction: row | row-reverse | column | column-reverse; }
  • flex-wrap:決定換行規則 .box{ flex-wrap: nowrap | wrap | wrap-reverse; }
  • flex-flow: .box { flex-flow: || ; }
  • justify-content:對其方式,水平主軸對齊方式
  • align-items:對齊方式,豎直軸線方向

專案的屬性(元素的屬性):

  • order屬性:定義專案的排列順序,順序越小,排列越靠前,預設為0
  • flex-grow屬性:定義專案的放大比例,即使存在空間,也不會放大
  • flex-shrink屬性:定義了專案的縮小比例,當空間不足的情況下會等比例的縮小,如果定義個item的flow-shrink為0,則為不縮小
  • flex-basis屬性:定義了在分配多餘的空間,專案佔據的空間。
  • flex:是flex-grow和flex-shrink、flex-basis的簡寫,預設值為0 1 auto。
  • align-self:允許單個專案與其他專案不一樣的對齊方式,可以覆蓋align-items,預設屬性為auto,表示繼承父元素的align-items

比如說,用flex實現聖盃佈局

6.BFC(塊級格式化上下文,用於清楚浮動,防止margin重疊等)

直譯成:塊級格式化上下文,是一個獨立的渲染區域,並且有一定的佈局規則。

  • BFC區域不會與float box重疊
  • BFC是頁面上的一個獨立容器,子元素不會影響到外面
  • 計算BFC的高度時,浮動元素也會參與計算

那些元素會生成BFC:

  • 根元素
  • float不為none的元素
  • position為fixed和absolute的元素
  • display為inline-block、table-cell、table-caption,flex,inline-flex的元素
  • overflow不為visible的元素

7.垂直居中的方法

(1)margin:auto法

css:

div{
  width: 400px;
  height: 400px;
  position: relative;
  border: 1px solid #465468;
 }
 img{
      position: absolute;
      margin: auto;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
 }
複製程式碼

html:

<div>
 <img src="mm.jpg">
</div>
複製程式碼

定位為上下左右為0,margin:0可以實現脫離文件流的居中.

(2)margin負值法

.container{
  width: 500px;
  height: 400px;
  border: 2px solid #379;
  position: relative;
}
.inner{
  width: 480px;
  height: 380px;
  background-color: #746;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -190px; /*height的一半*/
  margin-left: -240px; /*width的一半*/
 }
複製程式碼

補充:其實這裡也可以將marin-top和margin-left負值替換成, transform:translateX(-50%)和transform:translateY(-50%)

(3)table-cell(未脫離文件流的)

設定父元素的display:table-cell,並且vertical-align:middle,這樣子元素可以實現垂直居中。

css:
div{
    width: 300px;
    height: 300px;
    border: 3px solid #555;
    display: table-cell;
    vertical-align: middle;
    text-align: center;
}
img{
    vertical-align: middle;
}
複製程式碼

(4)利用flex

將父元素設定為display:flex,並且設定align-items:center;justify-content:center;

css:
.container{
      width: 300px;
      height: 200px;
      border: 3px solid #546461;
      display: -webkit-flex;
      display: flex;
      -webkit-align-items: center;
      align-items: center;
      -webkit-justify-content: center;
      justify-content: center;
 }
 .inner{
      border: 3px solid #458761;
      padding: 20px;
 }
複製程式碼

8.關於js動畫和css3動畫的差異性

渲染執行緒分為main thread和compositor thread,如果css動畫只改變transform和opacity,這時整個CSS動畫得以在compositor trhead完成(而js動畫則會在main thread執行,然後出發compositor thread進行下一步操作),特別注意的是如果改變transform和opacity是不會layout或者paint的。 區別:

  • 功能涵蓋面,js比css大
  • 實現/重構難度不一,CSS3比js更加簡單,效能跳優方向固定
  • 對幀速表現不好的低版本瀏覽器,css3可以做到自然降級
  • css動畫有天然事件支援
  • css3有相容性問題

9.塊元素和行元素

塊元素:獨佔一行,並且有自動填滿父元素,可以設定margin和pading以及高度和寬度 行元素:不會獨佔一行,width和height會失效,並且在垂直方向的padding和margin會失 效。

10.多行元素的文字省略號

 display: -webkit-box
-webkit-box-orient:vertical
-web-line-clamp:3
overflow:hidden
複製程式碼

11.visibility=hidden, opacity=0,display:none

opacity=0,該元素隱藏起來了,但不會改變頁面佈局,並且,如果該元素已經繫結一些事件,如click事件,那麼點選該區域,也能觸發點選事件的visibility=hidden,該元素隱藏起來了,但不會改變頁面佈局,但是不會觸發該元素已經繫結的事件display=none,把元素隱藏起來,並且會改變頁面佈局,可以理解成在頁面中把該元素刪除掉一樣。

12.雙邊距重疊問題(外邊距摺疊)

多個相鄰(兄弟或者父子關係)普通流的塊元素垂直方向marigin會重疊

摺疊的結果為:

兩個相鄰的外邊距都是正數時,摺疊結果是它們兩者之間較大的值。 兩個相鄰的外邊距都是負數時,摺疊結果是兩者絕對值的較大值。 兩個外邊距一正一負時,摺疊結果是兩者的相加的和。

相關文章