合格前端系列第九彈-前端面試那些事

腦子裏陸陸續續過出來的一些面試題,文章會不斷更新javascript

項目相關

  1. 自我介紹:職業經歷,項目經歷
  2. 選一個你以爲印象最深的項目講一講,而後會從項目裏面切入到 web 基礎(html/css/js),這一塊大概會聊 20-30 分鐘,因此必定要提早選好一個本身作過的得意的項目,花一點時間捋一捋你以爲項目中出色的點,用到了比較 hack,比較酷炫的方法解決了哪些痛點。

JS 基礎(ES5)

  1. 原型:這裏能夠談不少,只要圍繞 [[ prototype ]] 談,都沒啥問題
  2. 閉包:牽扯做用域,能夠二者聯繫起來一塊兒談
  3. 做用域:詞法做用域,動態做用域
  4. this:不一樣狀況的調用,this 指向分別如何。順帶能夠提一下 es6 中箭頭函數沒有 this, arguments, super 等,這些只依賴包含箭頭函數最接近的函數
  5. call,apply,bind 三者用法和區別:參數、綁定規則(顯示綁定和強綁定),運行效率(最終都會轉換成一個一個的參數去運行)、運行狀況(call,apply 當即執行,bind 是return 出一個 this 「固定」的函數,這也是爲何 bind 是強綁定的一個緣由)。

注:「固定」這個詞的含義,它指的固定是指只要傳進去了 context,則 bind 中 return 出來的函數 this 便一直指向 context,除非 context 是個變量 6. 變量聲明提高:js 代碼在運行前都會進行 AST 解析,函數申明默認會提到當前做用域最前面,變量申明也會進行提高。但賦值不會獲得提高。關於 AST 解析,這裏也能夠說是造成詞法做用域的主要緣由css

這裏若是面試官問到2,3,4,5,6中的一點,你可以把2,3,4,5,6整理到一塊兒,串聯起來進行統一的回答效果極佳html

具體參考 從指向看JavaScriptvue

JS 基礎(ES6)

  1. let,const:let 產生塊級做用域(一般配合 for 循環或者 {} 進行使用產生塊級做用域),const 申明的變量是常量(內存地址不變)
  2. Promise:這裏你談 promise 的時候,除了將他解決的痛點以及經常使用的 API 以外,最好進行拓展把 eventloop 帶進來好好講一下,microtask、macrotask 的執行順序,若是看過 promise 源碼,最好能夠談一談 原生 Promise 是如何實現的。Promise 的關鍵點在於callback 的兩個參數,一個是 resovle,一個是 reject。還有就是 Promise 的鏈式調用(Promise.then(),每個 then 都是一個責任人)。

詳細參考 my-promisejava

  1. Generator:遍歷器對象生成函數,最大的特色是能夠交出函數的執行權
  • function 關鍵字與函數名之間有一個星號;
  • 函數體內部使用 yield 表達式,定義不一樣的內部狀態;
  • next 指針移向下一個狀態

這裏你能夠說說 Generator 的異步編程,以及它的語法糖 asyncawiat,傳統的異步編程。ES6 以前,異步編程大體以下node

  • 回調函數
  • 事件監聽
  • 發佈/訂閱

傳統異步編程方案之一:協程,多個線程互相協做,完成異步任務。react

  1. async、await:Generator 函數的語法糖。有更好的語義、更好的適用性、返回值是 Promise。
  • async => *
  • await => yield

基本用法webpack

async function timeout (ms) {
  await new Promise((resolve) => {
    setTimeout(resolve, ms)    
  })
}
async function asyncConsole (value, ms) {
  await timeout(ms)
  console.log(value)
}
asyncConsole('hello async and await', 1000)
複製代碼

注:最好把2,3,4 連到一塊兒講css3

  1. AMD,CMD,CommonJs,ES6 Module:解決原始無模塊化的痛點
  • AMD:requirejs 在推廣過程當中對模塊定義的規範化產出,提早執行,推崇依賴前置
  • CMD:seajs 在推廣過程當中對模塊定義的規範化產出,延遲執行,推崇依賴就近
  • CommonJs:模塊輸出的是一個值的 copy,運行時加載,加載的是一個對象(module.exports 屬性),該對象只有在腳本運行完纔會生成
  • ES6 Module:模塊輸出的是一個值的引用,編譯時輸出接口,ES6 模塊不是對象,它對外接口只是一種靜態定義,在代碼靜態解析階段就會生成。

CSS相關

  1. 左邊定寬,右邊自適應方案:float + margin,float + calc
/* 方案1 */
.left {
  width: 120px;
  float: left;
}
.right {
  margin-left: 120px;
}
/* 方案2 */
.left {
  width: 120px;
  float: left;
}
.right {
  width: calc(100% - 120px);
  float: left;
}
複製代碼
  1. 左右兩邊定寬,中間自適應:float,float + calc, 聖盃佈局(設置BFC,margin負值法),flex
.wrap {
  width: 100%;
  height: 200px;
}
.wrap > div {
  height: 100%;
}
/* 方案1 */
.left {
  width: 120px;
  float: left;
}
.right {
  float: right;
  width: 120px;
}
.center {
  margin: 0 120px; 
}
/* 方案2 */
.left {
  width: 120px;
  float: left;
}
.right {
  float: right;
  width: 120px;
}
.center {
  width: calc(100% - 240px);
  margin-left: 120px;
}
/* 方案3 */
.wrap {
  display: flex;
}
.left {
  width: 120px;
}
.right {
  width: 120px;
}
.center {
  flex: 1;
}
複製代碼
  1. 左右居中
  • 行內元素: text-align: center
  • 定寬塊狀元素: 左右 margin 值爲 auto
  • 不定寬塊狀元素: table佈局,position + transform
/* 方案1 */
.wrap {
  text-align: center
}
.center {
  display: inline;
  /* or */
  /* display: inline-block; */
}
/* 方案2 */
.center {
  width: 100px;
  margin: 0 auto;
}
/* 方案2 */
.wrap {
  position: relative;
}
.center {
  position: absulote;
  left: 50%;
  transform: translateX(-50%);
}
複製代碼
  1. 上下垂直居中:
  • 定高:margin,position + margin(負值)
  • 不定高:position + transform,flex,IFC + vertical-align:middle
/* 定高方案1 */
.center {
  height: 100px;
  margin: 50px 0;   
}
/* 定高方案2 */
.center {
  height: 100px;
  position: absolute;
  top: 50%;
  margin-top: -25px;
}
/* 不定高方案1 */
.center {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}
/* 不定高方案2 */
.wrap {
  display: flex;
  align-items: center;
}
.center {
  width: 100%;
}
/* 不定高方案3 */
/* 設置 inline-block 則會在外層產生 IFC,高度設爲 100% 撐開 wrap 的高度 */
.wrap::before {
  content: '';
  height: 100%;
  display: inline-block;
  vertical-align: middle;
}
.wrap {
  text-align: center;
}
.center {
  display: inline-block;  
  vertical-align: middle;
}
複製代碼
  1. 盒模型:content(元素內容) + padding(內邊距) + border(邊框) + margin(外邊距)

延伸: box-sizingnginx

  • content-box:默認值,總寬度 = margin + border + padding + width
  • border-box:盒子寬度包含 padding 和 border,總寬度 = margin + width
  • inherit:從父元素繼承 box-sizing 屬性
  1. BFC、IFC、GFC、FFC:FC(Formatting Contexts),格式化上下文
  • BFC:塊級格式化上下文,容器裏面的子元素不會在佈局上影響到外面的元素,反之也是如此(按照這個理念來想,只要脫離文檔流,確定就能產生 BFC)。產生 BFC 方式以下

float 的值不爲 none。

overflow 的值不爲 visible。

position 的值不爲 relative 和 static。

display 的值爲 table-cell, table-caption, inline-block中的任何一個。

用處?常見的多欄佈局,結合塊級別元素浮動,裏面的元素則是在一個相對隔離的環境裏運行。

  • IFC:內聯格式化上下文,IFC 的 line box(線框)高度由其包含行內元素中最高的實際高度計算而來(不受到豎直方向的 padding/margin 影響)。

IFC中的line box通常左右都貼緊整個 IFC,可是會由於 float 元素而擾亂。float 元素會位於 IFC 與 line box 之間,使得 line box 寬度縮短。 同個 ifc 下的多個 line box 高度會不一樣。 IFC 中時不可能有塊級元素的,當插入塊級元素時(如 p 中插入 div )會產生兩個匿名塊與 div 分隔開,即產生兩個 IFC ,每一個 IFC 對外表現爲塊級元素,與 div 垂直排列。

用處?

水平居中:當一個塊要在環境中水平居中時,設置其爲 inline-block 則會在外層產生IFC,經過 text-align 則可使其水平居中。

垂直居中:建立一個 IFC,用其中一個元素撐開父元素的高度,而後設置其 vertical-align: middle,其餘行內元素則能夠在此父元素下垂直居中

  • GFC:網格佈局格式化上下文(display: grid)
  • FFC:自適應格式化上下文(display: flex)

詳細參考 css3中的BFC,IFC,GFC和FFC

框架相關

  1. 數據雙向綁定原理:常見數據綁定的方案
  • Object.defineProperty(vue):劫持數據的 getter 和 setter
  • 髒值檢測(angularjs):經過特定事件進行輪循
  • 發佈/訂閱模式:經過消息發佈並將消息進行訂閱

詳細細節參考 實現一個屬於咱們本身的簡易MVVM庫

擴充:如何監聽數組變化

  1. VDOM:三個 part,
  • 虛擬節點類,將真實 DOM 節點用 js 對象的形式進行展現,並提供 render 方法,將虛擬節點渲染成真實 DOM
  • 節點 diff 比較:對虛擬節點進行 js 層面的計算,並將不一樣的操做都記錄到 patch 對象
  • re-render:解析 patch 對象,進行 re-render

詳細請參考 實現Virtual Dom && Diff

補充1:VDOM 的必要性?

  • 建立真實DOM的代價高:真實的 DOM 節點 node 實現的屬性不少,而 vnode 僅僅實現一些必要的屬性,相比起來,建立一個 vnode 的成本比較低。

  • 觸發屢次瀏覽器重繪及迴流:使用 vnode ,至關於加了一個緩衝,讓一次數據變更所帶來的全部 node 變化,先在 vnode 中進行修改,而後 diff 以後對全部產生差別的節點集中一次對 DOM tree 進行修改,以減小瀏覽器的重繪及迴流。

補充2:vue 爲何採用 vdom?

引入 Virtual DOM 在性能方面的考量僅僅是一方面。

性能受場景的影響是很是大的,不一樣的場景可能形成不一樣實現方案之間成倍的性能差距,因此依賴細粒度綁定及 Virtual DOM 哪一個的性能更好還真不是一個容易下定論的問題。

Vue 之因此引入了 Virtual DOM,更重要的緣由是爲了解耦 HTML 依賴,這帶來兩個很是重要的好處是:

  • 再也不依賴 HTML 解析器進行模版解析,能夠進行更多的 AOT 工做提升運行時效率:經過模版 AOT 編譯,Vue 的運行時體積能夠進一步壓縮,運行時效率能夠進一步提高;
  • 能夠渲染到 DOM 之外的平臺,實現 SSR、同構渲染這些高級特性,Weex 等框架應用的就是這一特性。

綜上,Virtual DOM 在性能上的收益並非最主要的,更重要的是它使得 Vue 具有了現代框架應有的高級特性。

  1. vue 和 react 區別
  • 相同點:都支持 ssr,都有 vdom,組件化開發,實現 webComponents 規範,數據驅動等
  • 不一樣點:vue 是雙向數據流(固然爲了實現單數據流方便管理組件狀態,vuex 便出現了),react 是單向數據流。vue 的 vdom 是追蹤每一個組件的依賴關係,不會渲染整個組件樹,react 每當應該狀態被改變時,所有子組件都會 re-render。

上面提到的每一個點,具體細節還得看本身的理解

  1. 爲何用 vue :簡潔、輕快、舒服、沒了

網絡基礎類

  1. 跨域:不少種方法,但萬變不離其宗,都是爲了搞定同源策略。重用的有 jsonp、iframe、cors、img、HTML5 postMessage等等。其中用到 html 標籤進行跨域的原理就是 html 不受同源策略影響。但只是接受 Get 的請求方式,這個得清楚。

詳細內容傳送門

延伸1:img iframe script 來發送跨域請求有什麼優缺點?

  • iframe

優勢:跨域完畢以後DOM操做和互相之間的JavaScript調用都是沒有問題的

缺點:1.若結果要以URL參數傳遞,這就意味着在結果數據量很大的時候須要分割傳遞,巨煩。2.還有一個是iframe自己帶來的,母頁面和iframe自己的交互自己就有安全性限制。

  • script

優勢:能夠直接返回json格式的數據,方便處理

缺點:只接受GET請求方式

  • 圖片ping

優勢:能夠訪問任何url,通常用來進行點擊追蹤,作頁面分析經常使用的方法

缺點:不能訪問響應文本,只能監聽是否響應

延伸2:配合 webpack 進行反向代理?

webpack 在 devServer 選項裏面提供了一個 proxy 的參數供開發人員進行反向代理

'/api': {
  target: 'http://www.example.com', // your target host
  changeOrigin: true, // needed for virtual hosted sites
  pathRewrite: {
    '^/api': ''  // rewrite path
  }
},
複製代碼

而後再配合 http-proxy-middleware 插件對 api 請求地址進行代理

const express = require('express');
const proxy = require('http-proxy-middleware');
// proxy api requests
const exampleProxy = proxy(options); // 這裏的 options 就是 webpack 裏面的 proxy 選項對應的每一個選項

// mount `exampleProxy` in web server
const app = express();
app.use('/api', exampleProxy);
app.listen(3000);
複製代碼

而後再用 nginx 把容許跨域的源地址添加到報頭裏面便可

說到 nginx ,能夠再談談 CORS 配置,大體以下

location / {
  if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' '*';  
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; 
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Headers' 'DNT, X-Mx-ReqToken, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type';  
    add_header 'Access-Control-Max-Age' 86400;  
    add_header 'Content-Type' 'text/plain charset=UTF-8';  
    add_header 'Content-Length' 0;  
    return 200;  
  }
}
複製代碼
  1. http 無狀態無鏈接
  • http 協議對於事務處理沒有記憶能力
  • 對同一個url請求沒有上下文關係
  • 每次的請求都是獨立的,它的執行狀況和結果與前面的請求和以後的請求是無直接關係的,它不會受前面的請求應答狀況直接影響,也不會直接影響後面的請求應答狀況
  • 服務器中沒有保存客戶端的狀態,客戶端必須每次帶上本身的狀態去請求服務器
  • 人生若只如初見,請求過的資源下一次會繼續進行請求

http協議無狀態中的 狀態 到底指的是什麼?!

【狀態】的含義就是:客戶端和服務器在某次會話中產生的數據

那麼對應的【無狀態】就意味着:這些數據不會被保留

but

  • 經過增長cookie和session機制,如今的網絡請求實際上是有狀態的
  • 在沒有狀態的http協議下,服務器也必定會保留你每次網絡請求對數據的修改,但這跟保留每次訪問的數據是不同的,保留的只是會話產生的結果,而沒有保留會話
  1. http-cache:就是 http 緩存咯

首先得明確 http 緩存的好處

  • 減小了冗餘的數據傳輸,減小網費
  • 減小服務器端的壓力
  • Web 緩存可以減小延遲與網絡阻塞,進而減小顯示某個資源所用的時間
  • 加快客戶端加載網頁的速度

常見 http 緩存的類型

  • 私有緩存(通常爲本地瀏覽器緩存)
  • 代理緩存

而後談談本地緩存

本地緩存是指瀏覽器請求資源時命中了瀏覽器本地的緩存資源,瀏覽器並不會發送真正的請求給服務器了。它的執行過程是:

  • 第一次瀏覽器發送請求給服務器時,此時瀏覽器尚未本地緩存副本,服務器返回資源給瀏覽器,響應碼是200 OK,瀏覽器收到資源後,把資源和對應的響應頭一塊兒緩存下來。
  • 第二次瀏覽器準備發送請求給服務器時候,瀏覽器會先檢查上一次服務端返回的響應頭信息中的Cache-Control,它的值是一個相對值,單位爲秒,表示資源在客戶端緩存的最大有效期,過時時間爲第一次請求的時間減去Cache-Control的值,過時時間跟當前的請求時間比較,若是本地緩存資源沒過時,那麼命中緩存,再也不請求服務器。
  • 若是沒有命中,瀏覽器就會把請求發送給服務器,進入緩存協商階段。

與本地緩存相關的頭有:Cache-Control、Expires,Cache-Control有多個可選值表明不一樣的意義,而Expires就是一個日期格式的絕對值。

Cache-Control

Cache-Control是HTPP緩存策略中最重要的頭,它是HTTP/1.1中出現的,它由以下幾個值

  • no-cache:不使用本地緩存。須要使用緩存協商,先與服務器確認返回的響應是否被更改,若是以前的響應中存在ETag,那麼請求的時候會與服務端驗證,若是資源未被更改,則能夠避免從新下載。
  • no-store:直接禁止遊覽器緩存數據,每次用戶請求該資源,都會向服務器發送一個請求,每次都會下載完整的資源。
  • public:能夠被全部的用戶緩存,包括終端用戶和CDN等中間代理服務器。
  • private:只能被終端用戶的瀏覽器緩存,不容許CDN等中繼緩存服務器對其緩存。
  • max-age:從當前請求開始,容許獲取的響應被重用的最長時間(秒)。

例如:

Cache-Control: public, max-age=1000
複製代碼

表示資源能夠被全部用戶以及代理服務器緩存,最長時間爲1000秒。

Expires

Expires是HTTP/1.0出現的頭信息,一樣是用於決定本地緩存策略的頭,它是一個絕對時間,時間格式是如Mon, 10 Jun 2015 21:31:12 GMT,只要發送請求時間是在Expires以前,那麼本地緩存始終有效,不然就會去服務器發送請求獲取新的資源。若是同時出現Cache-Control:max-age和Expires,那麼max-age優先級更高。他們能夠這樣組合使用

Cache-Control: public
Expires: Wed, Jan 10 2018 00:27:04 GMT
複製代碼

所謂的緩存協商

當第一次請求時服務器返回的響應頭中存在如下狀況時

  • 沒有Cache-Control和Expires
  • Cache-Control和Expires過時了
  • Cache-Control的屬性設置爲no-cache時

那麼瀏覽器第二次請求時就會與服務器進行協商,詢問瀏覽器中的緩存資源是否是舊版本,需不須要更新,此時,服務器就會作出判斷,若是緩存和服務端資源的最新版本是一致的,那麼就無需再次下載該資源,服務端直接返回304 Not Modified 狀態碼,若是服務器發現瀏覽器中的緩存已是舊版本了,那麼服務器就會把最新資源的完整內容返回給瀏覽器,狀態碼就是200 Ok,那麼服務端是根據什麼來判斷瀏覽器的緩存是否是最新的呢?實際上是根據HTTP的另外兩組頭信息,分別是:Last-Modified/If-Modified-Since 與 ETag/If-None-Match

Last-Modified 與 If-Modified-Since

  • 瀏覽器第一次請求資源時,服務器會把資源的最新修改時間Last-Modified:Thu, 29 Dec 2011 18:23:55 GMT放在響應頭中返回給瀏覽器
  • 第二次請求時,瀏覽器就會把上一次服務器返回的修改時間放在請求頭If-Modified-Since:Thu, 29 Dec 2011 18:23:55發送給服務器,服務器就會拿這個時間跟服務器上的資源的最新修改時間進行對比

若是二者相等或者大於服務器上的最新修改時間,那麼表示瀏覽器的緩存是有效的,此時緩存會命中,服務器就再也不返回內容給瀏覽器了,同時Last-Modified頭也不會返回,由於資源沒被修改,返回了也沒什麼意義。若是沒命中緩存則最新修改的資源連同Last-Modified頭一塊兒返回。

第一次請求返回的響應頭:

Cache-Control:max-age=3600
Expires: Fri, Jan 12 2018 00:27:04 GMT
Last-Modified: Wed, Jan 10 2018 00:27:04 GMT
複製代碼

第二次請求的請求頭信息:

If-Modified-Since: Wed, Jan 10 2018 00:27:04 GMT
複製代碼

這組頭信息是基於資源的修改時間來判斷資源有沒有更新,另外一種方式就是根據資源的內容來判斷,就是接下來要討論的ETag與If-None-Match

ETag與If-None-Match

ETag/If-None-Match與Last-Modified/If-Modified-Since的流程實際上是相似的,惟一的區別是它基於資源的內容的摘要信息(好比MD5 hash)來判斷

瀏覽器發送第二次請求時,會把第一次的響應頭信息ETag的值放在If-None-Match的請求頭中發送到服務器,與最新的資源的摘要信息對比,若是相等,取瀏覽器緩存,不然內容有更新,最新的資源連同最新的摘要信息返回。用ETag的好處是若是由於某種緣由到時資源的修改時間沒改變,那麼用ETag就能區分資源是否是有被更新。

第一次請求返回的響應頭:

Cache-Control: public, max-age=31536000
ETag: "15f0fff99ed5aae4edffdd6496d7131f"
複製代碼

第二次請求的請求頭信息:

If-None-Match: "15f0fff99ed5aae4edffdd6496d7131f"
複製代碼
  1. cookie 和 session
  • session: 是一個抽象概念,開發者爲了實現中斷和繼續等操做,將 user agent 和 server 之間一對一的交互,抽象爲「會話」,進而衍生出「會話狀態」,也就是 session 的概念
  • cookie:它是一個世紀存在的東西,http 協議中定義在 header 中的字段,能夠認爲是 session 的一種後端無狀態實現

如今咱們常說的 「session」,是爲了繞開 cookie 的各類限制,一般藉助 cookie 自己和後端存儲實現的,一種更高級的會話狀態實現

session 的常見實現要藉助cookie來發送 sessionID

  1. 安全問題,如 XSS 和 CSRF
  • XSS:跨站腳本攻擊,是一種網站應用程序的安全漏洞攻擊,是代碼注入的一種。常見方式是將惡意代碼注入合法代碼裏隱藏起來,再誘發惡意代碼,從而進行各類各樣的非法活動。

防範:記住一點 「全部用戶輸入都是不可信的」,因此得作輸入過濾和轉義

詳細點擊 對於跨站腳本攻擊(XSS攻擊)的理解和總結

  • CSRF:跨站請求僞造,也稱 XSRF,是一種挾制用戶在當前已登陸的Web應用程序上執行非本意的操做的攻擊方法。與 XSS 相比,XSS利用的是用戶對指定網站的信任,CSRF利用的是網站對用戶網頁瀏覽器的信任。

防範:用戶操做驗證(驗證碼),額外驗證機制(token使用)等

詳細點擊 對於跨站僞造請求(CSRF)的理解和總結

我的準備從新撿回本身的公衆號了,以後每週保證一篇高質量好文,感興趣的小夥伴能夠關注一波。

相關文章
相關標籤/搜索