本文主要給你們帶來一些我面試的經歷和經驗,但願對正在求職的同窗有所幫助。我先大體說下面試以前的我的狀況:2017年7月正式入職海康威視數字技術股份有限公司,使用Vue.js技術棧。css
我寫的篇幅可能有點長,若是隻想當作功的面試請直接從阿里企業智能事業部(一面)開始,你們見諒哈。html
Hi,你們好,咱們是阿里巴巴新成立的BU,目前還有大量的Web前端職位空缺,機會可貴,但願正在找工做的同窗們能夠來試試:前端
真的機會可貴哦,若是想更多瞭解咱們BU以及找我內推的同事加我釘釘或者微信(純粹找我瞭解或者溝通技術也行,啊哈哈):18768107826vue
個人簡歷只是簡單的用MD作了一份,大體包含了如下幾個部分:react
小提示:在基本資料裏必定要填寫正確的郵箱地址,我在前期面試的時候都沒有打開郵箱查看面試狀況,致使一些面試的時間點和麪試結果都不清楚(一直覺得會發短信通知)。css3
若是去現場面試,必定要記得帶上筆和簡歷。一方面你給面試官的簡歷一定是最新的(在不斷面試的過程當中你一定會修改簡歷),另外一方面這也會給面試官一種很是舒心的感受。git
對於簡歷這裏提一點,在寫本身的專業技能和項目經歷時儘可能不要給本身挖坑,這裏展現一下個人專業技能(我會的很少):github
切忌寫一大堆讓人感受花裏胡哨的技能,尤爲是一些很淺顯的技能(基本技能除外)。若是你有一些別人很難替代的技能,那這些技能就是亮點了,我這裏就沒什麼亮點技能。有些技能你會可是不熟練,你能夠適當的在你的項目經歷中體現出來。對於項目經歷儘可能挑本身以爲很是有技術含量的項目進行說明(寧缺毋濫),對於本身參加過但不是特別熟悉的項目儘可能不要填寫,防止給本身挖坑。面試
小提示:這裏附上的個人面試簡歷供你們參考。感謝jsliang的文章2019 面試系列 - 簡歷,你們製做簡歷時也能夠參考這篇文章。算法
在投遞簡歷時你們千萬不要被招聘信息中的要求嚇到,記得有一次投遞簡歷時我對招聘者說自身不太符合要求,招聘者當時說要求都是唬人的,以爲有興趣就投,有些招聘要求可能正是你將來學習或者深刻的領域。
簡歷製做完後我大概投了四家公司:有贊、滴滴、51信用卡和阿里。其中有贊掛在二面,滴滴掛在一面,51信用卡掛在一面,阿里兩個部門掛在一面,一個部門面試成功。不少面試者的經歷可能都是像我這樣,在一次次的面試失敗中不斷的總結進步,最終拿到理想的Offer。
小提示:建議你們在投遞簡歷時能夠先投遞一些試水的小公司,先檢驗一下本身是否是能夠勝任這些公司的面試。同時在每一次面試完後記得把面試官提問的問題記錄下來,對於沒有答上來的問題仍是要好好搞懂或者實踐一下,由於頗有可能下一家的面試官會問一樣的問題。
在面試的過程當中,這裏我給出幾點意見:
接下來我會按照面試順序給出面試題以及本身理解的一些答案:
!important
小提示:這個問題重點是BFC是什麼,BFC觸發的條件有哪些,BFC能夠幹什麼。這裏我試着講解了一下Boostrap的清除浮動(display:table建立匿名table-cell間接觸發BFC),若是有看到別的場景使用或者自身有使用的場景能夠嘗試講解一下使用技巧。這樣可讓面試官以爲你不只僅知道他問的東西是什麼,你還能很好的使用它。
BFC 全稱爲塊級格式化上下文 (Block Formatting Context) 。BFC是 W3C CSS 2.1 規範中的一個概念,它決定了元素如何對其內容進行定位以及與其餘元素的關係和相互做用,當涉及到可視化佈局的時候,Block Formatting Context提供了一個環境,HTML元素在這個環境中按照必定規則進行佈局。一個環境中的元素不會影響到其它環境中的佈局。好比浮動元素會造成BFC,浮動元素內部子元素的主要受該浮動元素影響,兩個浮動元素之間是互不影響的。這裏有點相似一個BFC就是一個獨立的行政單位的意思。能夠說BFC就是一個做用範圍,把它理解成是一個獨立的容器,而且這個容器裏box的佈局與這個容器外的box絕不相干。
float
不是
none
)
position
爲
absolute
或
fixed
)
display: inline-block
)
display: table-cell
,HTML表格單元格默認屬性)
display: table-caption
, HTML表格標題默認屬性)
overflow
且值不是
visible
的塊元素
flex
或
inline-flex
)
display: flow-root
column-span: all
float
+
overflow
)
包括內容區域、內邊距區域、邊框區域和外邊距區域。box-sizing: content-box
(W3C盒子模型):元素的寬高大小表現爲內容的大小。box-sizing: border-box
(IE盒子模型):元素的寬高表現爲內容 + 內邊距 + 邊框的大小。背景會延伸到邊框的外沿。
IE5.x和IE6在怪異模式中使用非標準的盒子模型,這些瀏覽器的width
屬性不是內容的寬度,而是內容、內邊距和邊框的寬度的總和。
小提示:這個問題面試官會要求說出幾種解決方法。
DOM結構
<divclass="box"><divclass="box-left"></div><divclass="box-right"></div></div>複製代碼
.box { height: 200px; } .box > div { height: 100%; } .box-left { width: 200px; float: left; background-color: blue; } .box-right { margin-left: 200px; background-color: red; }複製代碼
.box { height: 200px; } .box > div { height: 100%; } .box-left { width: 200px; float: left; background-color: blue; } .box-right { width: calc(100% - 200px); float: right; background-color: red; }複製代碼
.box { height: 200px; } .box > div { height: 100%; } .box-left { width: 200px; float: left; background-color: blue; } .box-right { overflow: hidden; background-color: red; }複製代碼
這裏不是最佳答案,應該是使用flex-basis
實現更合理
.box { height: 200px; display: flex; } .box > div { height: 100%; } .box-left { width: 200px; background-color: blue; } .box-right { flex: 1; // 設置flex-grow屬性爲1,默認爲0 overflow: hidden; background-color: red; }複製代碼
小提示:若是日常自身有使用場景可結合使用場景進行講解,好比我在這裏使用過的場景是CORS和Nginx反向代理。
小提示:若是你提到JSONP,面試官確定會問你整個詳細的實現過程,因此必定要搞懂JSONP的實現原理,若是不是很理解能夠本身起一個Express服務實踐一下。
Web前端事先定義一個用於獲取跨域響應數據的回調函數,並經過沒有同源策略限制的script標籤發起一個請求(將回調函數的名稱放到這個請求的query參數裏),而後服務端返回這個回調函數的執行,並將須要響應的數據放到回調函數的參數裏,前端的script標籤請求到這個執行的回調函數後會立馬執行,因而就拿到了執行的響應數據。
缺點:JSONP只能發起GET請求
這裏給出幾個連接:
前端構造一個惡意頁面,請求JSONP接口,收集服務端的敏感信息。若是JSONP接口還涉及一些敏感操做或信息(好比登陸、刪除等操做),那就更不安全了。
解決方法:驗證JSONP的調用來源(Referer),服務端判斷Referer是不是白名單,或者部署隨機Token來防護。
不嚴謹的 content-type致使的 XSS 漏洞,想象一下 JSONP 就是你請求 http://youdomain.com?callback=douniwan
, 而後返回 douniwan({ data })
,那假如請求 http://youdomain.com?callback=<script>alert(1)</script>
不就返回 <script>alert(1)</script>({ data })
了嗎,若是沒有嚴格定義好 Content-Type( Content-Type: application/json ),再加上沒有過濾 callback
參數,直接當 html 解析了,就是一個赤裸裸的 XSS 了。
解決方法:嚴格定義 Content-Type: application/json,而後嚴格過濾 callback
後的參數而且限制長度(進行字符轉義,例如<換成<,>換成>)等,這樣返回的腳本內容會變成文本格式,腳本將不會執行。
能夠將執行的代碼轉發到服務端進行校驗JSONP內容校驗,再返回校驗結果。
小提示:若是你回答跨域解決方案CORS,那麼面試官必定會問你實現CORS的響應頭信息Access-Control-Allow-Origin。
CORS(跨域資源共享 Cross-origin resource sharing)容許瀏覽器向跨域服務器發出XMLHttpRequest請求,從而克服跨域問題,它須要瀏覽器和服務器的同時支持。
請求方法是如下三種方法之一:
HTTP的請求頭信息不超出如下幾種字段:
後端的響應頭信息:
非簡單請求是那種對服務器有特殊要求的請求,好比請求方法是PUT或DELETE,或者Content-Type字段的類型是application/json。非簡單請求的CORS請求,會在正式通訊以前,增長一次HTTP查詢請求,稱爲"預檢"請求(preflight)。
Access-Control-Request-Method:該字段是必須的,用來列出瀏覽器的CORS請求會用到哪些HTTP方法,上例是PUT。
Access-Control-Request-Headers:該字段是一個逗號分隔的字符串,指定瀏覽器CORS請求會額外發送的頭信息字段,上例是X-Custom-Header。
若是瀏覽器否認了"預檢"請求,會返回一個正常的HTTP迴應,可是沒有任何CORS相關的頭信息字段。這時,瀏覽器就會認定,服務器不一樣意預檢請求,所以觸發一個錯誤,被XMLHttpRequest對象的onerror回調函數捕獲。
postMessage
document.domain
相對於HTTP1.0,HTTP1.1的優化:
相對於HTTP1.1,HTTP2的優化:
小提示:若是日常有遇到過緩存的坑或者很好的利用緩存,能夠講解一下本身的使用場景。若是沒有使用注意過緩存問題你也能夠嘗試講解一下和咱們息息相關的Webpack構建(每一次構建靜態資源名稱的hash值都會變化),它其實就跟緩存相關。有興趣的同窗能夠查看張雲龍的博客大公司裏怎樣開發和部署前端代碼?。
緩存分爲強緩存和協商緩存。強緩存不過服務器,協商緩存須要過服務器,協商緩存返回的狀態碼是304。兩類緩存機制能夠同時存在,強緩存的優先級高於協商緩存。當執行強緩存時,如若緩存命中,則直接使用緩存數據庫中的數據,再也不進行緩存協商。
Expires(HTTP1.0):Exprires的值爲服務端返回的數據到期時間。當再次請求時的請求時間小於返回的此時間,則直接使用緩存數據。但因爲服務端時間和客戶端時間可能有偏差,這也將致使緩存命中的偏差。另外一方面,Expires是HTTP1.0的產物,故如今大多數使用Cache-Control替代。
缺點:使用的是絕對時間,若是服務端和客戶端的時間產生誤差,那麼會致使命中緩存產生誤差。
Pragma(HTTP1.0):HTTP1.0時的遺留字段,當值爲"no-cache"時強制驗證緩存,Pragma禁用緩存,若是又給Expires定義一個還未到期的時間,那麼Pragma字段的優先級會更高。服務端響應添加'Pragma': 'no-cache',瀏覽器表現行爲和刷新(F5)相似。
Cache-Control(HTTP1.1):有不少屬性,不一樣的屬性表明的意義也不一樣:
請注意no-cache指令不少人誤覺得是不緩存,這是不許確的,no-cache的意思是能夠緩存,但每次用應該去想服務器驗證緩存是否可用。no-store纔是不緩存內容。當在首部字段Cache-Control 有指定 max-age 指令時,比起首部字段 Expires,會優先處理 max-age 指令。命中強緩存的表現形式:Firefox瀏覽器表現爲一個灰色的200狀態碼。Chrome瀏覽器狀態碼錶現爲200 (from disk cache)或是200 OK (from memory cache)。
協商緩存須要進行對比判斷是否能夠使用緩存。瀏覽器第一次請求數據時,服務器會將緩存標識與數據一塊兒響應給客戶端,客戶端將它們備份至緩存中。再次請求時,客戶端會將緩存中的標識發送給服務器,服務器根據此標識判斷。若未失效,返回304狀態碼,瀏覽器拿到此狀態碼就能夠直接使用緩存數據了。
Last-Modified:服務器在響應請求時,會告訴瀏覽器資源的最後修改時間。
if-Modified-Since:瀏覽器再次請求服務器的時候,請求頭會包含此字段,後面跟着在緩存中得到的最後修改時間。服務端收到此請求頭髮現有if-Modified-Since,則與被請求資源的最後修改時間進行對比,若是一致則返回304和響應報文頭,瀏覽器只須要從緩存中獲取信息便可。
if-Unmodified-Since: 從某個時間點算起, 是否文件沒有被修改,使用的是相對時間,不須要關心客戶端和服務端的時間誤差。
這兩個的區別是一個是修改了才下載一個是沒修改才下載。若是在服務器上,一個資源被修改了,但其實際內容根本沒發生改變,會由於Last-Modified時間匹配不上而返回了整個實體給客戶端(即便客戶端緩存裏有個如出一轍的資源)。爲了解決這個問題,HTTP1.1推出了Etag。
Etag:服務器響應請求時,經過此字段告訴瀏覽器當前資源在服務器生成的惟一標識(生成規則由服務器決定)
If-Match:條件請求,攜帶上一次請求中資源的ETag,服務器根據這個字段判斷文件是否有新的修改
If-None-Match:再次請求服務器時,瀏覽器的請求報文頭部會包含此字段,後面的值爲在緩存中獲取的標識。服務器接收到次報文後發現If-None-Match則與被請求資源的惟一標識進行對比。
可是實際應用中因爲Etag的計算是使用算法來得出的,而算法會佔用服務端計算的資源,全部服務端的資源都是寶貴的,因此就不多使用Etag了。
對於大部分的場景均可以使用強緩存配合協商緩存解決,可是在一些特殊的地方可能須要選擇特殊的緩存策略
小提示:若是作過相似優化的同窗,可能就比較好回答,沒有作過相似優化的同窗能夠重點講解一下懶加載(固然我這裏被面試官追問過懶加載的Webpack配置問題)。同時不知道使用Vue技術棧的同窗們有沒有仔細觀察過Vue CLI 3構建的html文件中的link標籤的rel屬性。
require
方法
這種問題仍是附上參考連接
小提示:同類型的問題還能夠是原型鏈、繼承、閉包等,這種概念性的問題你確定不是一句兩句能說清楚的,建議在理解以後本身嘗試總結一下,如何把重要的知識點用簡短的話語說明白。
瞭解做用域鏈以前咱們要知道一下幾個概念:
函數的生命週期:
建立:JS解析引擎進行預解析,會將函數聲明提早,同時將該函數放到全局做用域中或當前函數的上一級函數的局部做用域中。
執行:JS引擎會將當前函數的局部變量和內部函數進行聲明提早,而後再執行業務代碼,當函數執行完退出時,釋放該函數的執行上下文,並註銷該函數的局部變量。
變量和函數的聲明:若是變量名和函數名聲明時相同,函數優先聲明。
Activetion Object(AO)、Variable Object(VO):
VO對應的是函數建立階段,JS解析引擎進行預解析時,全部的變量和函數的聲明,統稱爲Variable Object。該變量與執行上下文相關,知道本身的數據存儲在哪裏,而且知道如何訪問。VO是一個與執行上下文相關的特殊對象,它存儲着在上下文中聲明的如下內容:
AO對應的是函數執行階段,當函數被調用執行時,會創建一個執行上下文,該執行上下文包含了函數所需的全部變量,該變量共同組成了一個新的對象就是Activetion Object。該對象包含了:
做用域鏈:
當代碼在一個環境中建立時,會建立變量對象的一個做用域鏈(scope chain)來保證對執行環境有權訪問的變量和函數。做用域第一個對象始終是當前執行代碼所在環境的變量對象(VO)。若是是函數執行階段,那麼將其activation object(AO)做爲做用域鏈第一個對象,第二個對象是上級函數的執行上下文AO,下一個對象依次類推。
在《JavaScript深刻之變量對象》中講到,當查找變量的時候,會先從當前上下文的變量對象中查找,若是沒有找到,就會從父級(詞法層面上的父級)執行上下文的變量對象中查找,一直找到全局上下文的變量對象,也就是全局對象。這樣由多個執行上下文的變量對象構成的鏈表就叫作做用域鏈。
小提示:若是面試者使用的是Vue技術棧,那麼響應式原理是一個必問的問題,同時面試官常常也會問Vue 3.0在響應式原理上的優化方案。
若是對於響應式原理不是很清楚能夠查看我以前寫的文章基於Vue實現一個簡易MVVM/數據劫持的實現。
小提示:這個題目問到的機率仍是蠻大的,這裏面試官詢問了我瀏覽器端和Node端的Event Loop有什麼不一樣點。若是想要知道更多瀏覽器端的Event Loop機制能夠查看我以前寫的文章你真的理解$nextTick麼/JS引擎線程和事件觸發線程/事件循環機制。
事件觸發線程管理的任務隊列是如何產生的呢?事實上這些任務就是從JS引擎線程自己產生的,主線程在運行時會產生執行棧,棧中的代碼調用某些異步API時會在任務隊列中添加事件,棧中的代碼執行完畢後,就會讀取任務隊列中的事件,去執行事件對應的回調函數,如此循環往復,造成事件循環機制。JS中有兩種任務類型:微任務(microtask)和宏任務(macrotask),在ES6中,microtask稱爲 jobs,macrotask稱爲 task:
setTimeout
、
setInterval
、
setImmediate
、I/O 、UI rendering
process.nextTick
(Nodejs) 、
Promise
、
Object.observe
、
MutationObserver
Node.js中Event Loop和瀏覽器中Event Loop有什麼區別
┌───────────────────────┐ ┌─>│ timers │<————— 執行 setTimeout()、setInterval() 的回調 │ └──────────┬────────────┘ | |<-- 執行全部 NextTickQueue 以及 MicroTaskQueue 的回調 │ ┌──────────┴────────────┐ │ │ pendingcallbacks │<————— 執行由上一個 Tick 延遲下來的 I/O 回調(待完善,可忽略) │ └──────────┬────────────┘ | |<-- 執行全部 NextTickQueue 以及 MicroTaskQueue 的回調 │ ┌──────────┴────────────┐ │ │ idle, prepare │<————— 內部調用(可忽略) │ └──────────┬────────────┘ | |<-- 執行全部 NextTickQueue 以及 MicroTaskQueue 的回調 | | ┌───────────────┐ │ ┌──────────┴────────────┐ │ incoming: │ - (執行幾乎全部的回調,除了 closecallbacks、timers、setImmediate) │ │ poll │<─────┤ connections, │ │ └──────────┬────────────┘ │ data, etc. │ │ | | | | | └───────────────┘ | |<-- 執行全部 NextTickQueue 以及 MicroTaskQueue 的回調 | ┌──────────┴────────────┐ │ │ check │<————— setImmediate() 的回調將會在這個階段執行 │ └──────────┬────────────┘ | |<-- 執行全部 NextTickQueue 以及 MicroTaskQueue 的回調 │ ┌──────────┴────────────┐ └──┤ closecallbacks │<————— socket.on('close', ...) └───────────────────────┘複製代碼
Node.js中宏任務分紅了幾種類型,而且放在了不一樣的task queue裏。不一樣的task queue在執行順序上也有區別,微任務放在了每一個task queue的末尾:
setTimeout/setInterval
屬於 timers 類型;
setImmediate
屬於 check 類型;
process.nextTick
本質上屬於 MicroTask,可是它先於全部其餘 MicroTask 執行;
瀏覽器渲染過程以下:
什麼時候發生迴流:
什麼時候發生重繪(迴流必定會觸發重繪):
當頁面中元素樣式的改變並不影響它在文檔流中的位置時(例如:color、background-color、visibility等),瀏覽器會將新樣式賦予給元素並從新繪製它,這個過程稱爲重繪。
有時即便僅僅迴流一個單一的元素,它的父元素以及任何跟隨它的元素也會產生迴流。現代瀏覽器會對頻繁的迴流或重繪操做進行優化,瀏覽器會維護一個隊列,把全部引發迴流和重繪的操做放入隊列中,若是隊列中的任務數量或者時間間隔達到一個閾值的,瀏覽器就會將隊列清空,進行一次批處理,這樣能夠把屢次迴流和重繪變成一次。你訪問如下屬性或方法時,瀏覽器會馬上清空隊列:
clientWidth
、
clientHeight
、
clientTop
、
clientLeft
offsetWidth
、
offsetHeight
、
offsetTop
、
offsetLeft
scrollWidth
、
scrollHeight
、
scrollTop
、
scrollLeft
width
、
height
getComputedStyle()
getBoundingClientRect()
以上屬性和方法都須要返回最新的佈局信息,所以瀏覽器不得不清空隊列,觸發迴流重繪來返回正確的值。所以,咱們在修改樣式的時候,**最好避免使用上面列出的屬性,他們都會刷新渲染隊列。**若是要使用它們,最好將值緩存起來。
CSS:
position
屬性爲
absolute
或
fixed
的元素上
calc()
)
JavaScript:
documentFragment
,在它上面應用全部DOM操做,最後再把它添加到文檔中
display: none
,操做結束後再把它顯示出來。由於在display屬性爲none的元素上進行的DOM操做不會引起迴流和重繪
小提示:進入現場面試須要注意好好準備本身的簡歷,面試官通常會根據項目進行問答。
一開始面試官就發了兩張筆試題試卷,總共四道題目,大體考了如下知識點:
Array.prototype.map
的第二個參數
答完試卷面試官就開始問簡歷上的一些項目,我記得其中幾個問題以下(事實上他問的一些問題和簡歷不是很相關):
我當場就感覺到了面試官問的問題很敷衍,可能他以爲個人簡歷不夠好,又或者以爲我能力不行,接下來面試官又讓我作了一道算法題...
當時沒作出來,非科班出身可能作這些確實有些困難,也沒有系統的學習,面試官看我很困難的樣子,就換了一道題。
這道題仍是作出來了,畢竟比較簡單,而後面試官說今天先到這裏,面試結果會在一星期內通知,而後回來的那天晚上就收到了面試沒過的通知。
仍是蠻感謝此次現場面試的經歷,讓我知道若是自身不夠硬,到哪裏都會很被動。面試的好處不只僅在於檢驗本身到底有多少能力,更應該發現自身的不足,同時不斷的去彌補這些不足。因而我再次捧起以前擱置的《算法導論》,而且建立了一個算法學習演示文檔I-Algorithms,但願能夠簡化《算法導論》的一些理論知識,使你們對於算法的學習能夠變得更加系統全面和簡單,也但願經過這個學習使得算法面試會變得更加駕輕就熟,但願感興趣的同窗能夠star一下。
小提示:這裏我簡單講解了一下Vue中的
v-html
防範XSS攻擊。
XSS,即 Cross Site Script,中譯是跨站腳本攻擊;其本來縮寫是 CSS,但爲了和層疊樣式表(Cascading Style Sheet)有所區分,於是在安全領域叫作 XSS。
XSS 攻擊是指攻擊者在網站上注入惡意的客戶端代碼,經過惡意腳本對客戶端網頁進行篡改,從而在用戶瀏覽網頁時,對用戶瀏覽器進行控制或者獲取用戶隱私數據的一種攻擊方式。
攻擊者對客戶端網頁注入的惡意腳本通常包括 JavaScript,有時也會包含 HTML 和 Flash。有不少種方式進行 XSS 攻擊,但它們的共同點爲:將一些隱私數據像 cookie、session 發送給攻擊者,將受害者重定向到一個由攻擊者控制的網站,在受害者的機器上進行一些惡意操做。
XSS攻擊能夠分爲3類:反射型(非持久型)、存儲型(持久型)、基於DOM。
反射型 XSS 只是簡單地把用戶輸入的數據 「反射」 給瀏覽器,這種攻擊方式每每須要攻擊者誘使用戶點擊一個惡意連接(攻擊者能夠將惡意連接直接發送給受信任用戶,發送的方式有不少種,好比 email, 網站的私信、評論等,攻擊者能夠購買存在漏洞網站的廣告,將惡意連接插入在廣告的連接中),或者提交一個表單,或者進入一個惡意網站時,注入腳本進入被攻擊者的網站。最簡單的示例是訪問一個連接,服務端返回一個可執行腳本:
const http = require('http'); functionhandleReequest(req, res) { res.setHeader('Access-Control-Allow-Origin', '*'); res.writeHead(200, {'Content-Type': 'text/html; charset=UTF-8'}); res.write('<script>alert("反射型 XSS 攻擊")</script>'); res.end(); } const server = new http.Server(); server.listen(8001, '127.0.0.1'); server.on('request', handleReequest);複製代碼
存儲型 XSS 會把用戶輸入的數據 "存儲" 在服務器端,當瀏覽器請求數據時,腳本從服務器上傳回並執行。這種 XSS 攻擊具備很強的穩定性。比較常見的一個場景是攻擊者在社區或論壇上寫下一篇包含惡意 JavaScript 代碼的文章或評論,文章或評論發表後,全部訪問該文章或評論的用戶,都會在他們的瀏覽器中執行這段惡意的 JavaScript 代碼:
// 例如在評論中輸入如下留言 // 若是請求這段留言的時候服務端不作轉義處理,請求以後頁面會執行這段惡意代碼 <script>alert('xss 攻擊')</script>複製代碼
基於 DOM 的 XSS 攻擊是指經過惡意腳本修改頁面的 DOM 結構,是純粹發生在客戶端的攻擊:
<h2>XSS: </h2> <input type="text" id="input"> <buttonid="btn">Submit</button> <div id="div"></div> <script> const input = document.getElementById('input'); const btn = document.getElementById('btn'); const div = document.getElementById('div'); let val; input.addEventListener('change', (e) => { val = e.target.value; }, false); btn.addEventListener('click', () => { div.innerHTML = `<a href=${val}>testLink</a>` }, false); </script>複製代碼
點擊 Submit 按鈕後,會在當前頁面插入一個連接,其地址爲用戶的輸入內容。若是用戶在輸入時構造了以下內容:
onclick=alert(/xss/)複製代碼
用戶提交以後,頁面代碼就變成了:
<a href onlick="alert(/xss/)">testLink</a>複製代碼
此時,用戶點擊生成的連接,就會執行對應的腳本。
HttpOnly 防止劫取 Cookie:HttpOnly 最先由微軟提出,至今已經成爲一個標準。瀏覽器將禁止頁面的Javascript 訪問帶有 HttpOnly 屬性的Cookie。上文有說到,攻擊者能夠經過注入惡意腳本獲取用戶的 Cookie 信息。一般 Cookie 中都包含了用戶的登陸憑證信息,攻擊者在獲取到 Cookie 以後,則能夠發起 Cookie 劫持攻擊。因此,嚴格來講,HttpOnly 並不是阻止 XSS 攻擊,而是能阻止 XSS 攻擊後的 Cookie 劫持攻擊。
輸入檢查:不要相信用戶的任何輸入。對於用戶的任何輸入要進行檢查、過濾和轉義。創建可信任的字符和 HTML 標籤白名單,對於不在白名單之列的字符或者標籤進行過濾或編碼。在 XSS 防護中,輸入檢查通常是檢查用戶輸入的數據中是否包含 <,> 等特殊字符,若是存在,則對特殊字符進行過濾或編碼,這種方式也稱爲 XSS Filter。而在一些前端框架中,都會有一份 decodingMap, 用於對用戶輸入所包含的特殊字符或標籤進行編碼或過濾,如 <,>,script,防止 XSS 攻擊:
// vuejs 中的 decodingMap// 在 vuejs 中,若是輸入帶 script 標籤的內容,會直接過濾掉const decodingMap = { '<': '<', '>': '>', '"': '"', '&': '&', ' ': '\n' }複製代碼
輸出檢查:用戶的輸入會存在問題,服務端的輸出也會存在問題。通常來講,除富文本的輸出外,在變量輸出到 HTML 頁面時,能夠使用編碼或轉義的方式來防護 XSS 攻擊。例如利用 sanitize-html 對輸出內容進行有規則的過濾以後再輸出到頁面中。
CSRF,即 Cross Site Request Forgery,中譯是跨站請求僞造,是一種劫持受信任用戶向服務器發送非預期請求的攻擊方式。一般狀況下,CSRF 攻擊是攻擊者藉助受害者的 Cookie 騙取服務器的信任,能夠在受害者絕不知情的狀況下以受害者名義僞造請求發送給受攻擊服務器,從而在並未受權的狀況下執行在權限保護之下的操做。
Cookie 是服務器發送到用戶瀏覽器並保存在本地的一小塊數據,它會在瀏覽器下次向同一服務器再發起請求時被攜帶併發送到服務器上。Cookie 主要用於如下三個方面:
而瀏覽器所持有的 Cookie 分爲兩種:
res.setHeader('Set-Cookie', ['mycookie=222', 'test=3333; expires=Sat, 21 Jul 2018 00:00:00 GMT;']);複製代碼
上述代碼建立了兩個 Cookie:mycookie 和 test,前者屬於會話期 Cookie,後者則屬於持久性 Cookie。
使登陸用戶訪問攻擊者的網站,發起一個請求,因爲 Cookie 中包含了用戶的認證信息,當用戶訪問攻擊者準備的攻擊環境時,攻擊者就能夠對服務器發起 CSRF 攻擊。
在這個攻擊過程當中,攻擊者藉助受害者的 Cookie 騙取服務器的信任,但並不能拿到 Cookie,也看不到 Cookie 的內容。而對於服務器返回的結果,因爲瀏覽器同源策略的限制,攻擊者也沒法進行解析。(攻擊者的網站雖然是跨域的,可是他構造的連接是源網站的,跟源網站是同源的,因此可以攜帶cookie發起訪問)。
可是攻擊者沒法從返回的結果中獲得任何東西,他所能作的就是給服務器發送請求,以執行請求中所描述的命令,在服務器端直接改變數據的值,而非竊取服務器中的數據。例如刪除數據、修改數據,新增數據等,沒法獲取數據。
驗證碼:驗證碼被認爲是對抗 CSRF 攻擊最簡潔而有效的防護方法。從上述示例中能夠看出,CSRF 攻擊每每是在用戶不知情的狀況下構造了網絡請求。而驗證碼會強制用戶必須與應用進行交互,才能完成最終請求。由於一般狀況下,驗證碼可以很好地遏制 CSRF 攻擊。但驗證碼並非萬能的,由於出於用戶考慮,不能給網站全部的操做都加上驗證碼。所以,驗證碼只能做爲防護 CSRF 的一種輔助手段,而不能做爲最主要的解決方案。
Referer Check:根據 HTTP 協議,在 HTTP 頭中有一個字段叫 Referer,它記錄了該 HTTP 請求的來源地址。經過 Referer Check,能夠檢查請求是否來自合法的"源"。
添加token驗證:要抵禦 CSRF,關鍵在於在請求中放入攻擊者所不能僞造的信息,而且該信息不存在於 Cookie 之中。能夠在 HTTP 請求中以參數的形式加入一個隨機產生的 token,並在服務器端創建一個攔截器來驗證這個 token,若是請求中沒有 token 或者 token 內容不正確,則認爲多是 CSRF 攻擊而拒絕該請求。
小提示:這道題是給本身挖了一個坑,抱着學習的心態嘗試使用Graphql技術,卻沒有好好理解是在什麼場景下爲了解決什麼問題才應該使用,也沒有好好準備如何描述新技術,每每這種不熟悉的技術本身在簡歷中應該留存一些心眼,儘可能不要提,不然答不上來會很尷尬,讓面試官懷疑你的項目成分。
GraphQL是一種API查詢語言。API接口的返回值能夠從靜態變爲動態,即調用者來聲明接口返回什麼數據,能夠進一步解耦先後端。在Graphal中,預先定義Schema和聲明Type來達到動態獲取接口數據的目的:
Type簡單能夠分爲兩種,一種叫作Scalar Type(標量類型),另外一種叫作Object Type(對象類型):
Scalar Type(標量類型):內建的標量包含,String、Int、Float、Boolean、Enum
Object Type(對象類型):感受相似於TypeScript的接口類型
Type Modifier(類型修飾符):用於代表是否必填等
定義了字段的類型、數據的結構,描述了接口數據請求的規則
查詢類型:query(查詢)、mutation(更改)和subscription(訂閱)
提供相關Query所返回數據的邏輯。Query和與之對應的Resolver是同名的,這樣在GraphQL才能把它們對應起來。解析的過程多是遞歸的,只要遇到非標量類型,會嘗試繼續解析,若是遇到標量類型,那麼解析完成,這個過程叫作解析鏈。
小提示:若是面試者使用的是Vue技術棧,那麼
$nextTick
的原理是一個高頻問題,面試者藉此能夠追問的東西較多,例如瀏覽器的Event Loop、微任務和宏任務、Node.js的Event Loop、異步更新DOM(響應式的數據for循環改變了1000次爲何視圖只更新了一次)、$nextTick
歷史版本問題等等。
這個若是不是很清楚的具體可查看我以前寫的文章你真的理解$nextTick麼。
text-align:center
便可實現行內元素水平居中
margin:0 auto
便可(元素須要定寬)
margin:0 auto
便可(子元素不須要定寬)
// flex容器 <div class="box"> // flex項目 <div class="box-center"> </div> </div> .box { width: 200px; height: 200px; display: flex; // 使內部的flex項目水平居中 justify-content: center; background-color: pink; } /* .box-center { width: 50%; background-color: greenyellow; } */ 複製代碼
transform
(這個屬性還和GPU硬件加速、固定定位相關)
.box { width: 200px; height: 200px; position: relative; background-color: pink; } .box-center { position: absolute; left:50%; // width: 50%; height: 100%; // 經過 translate() 方法,元素從其當前位置移動,根據給定的 left(x 座標) 和 top(y 座標) 位置參數: // translate(x,y) 定義 2D 轉換。 // translateX(x) 定義轉換,只是用 X 軸的值。 // translateY(y) 定義轉換,只是用 Y 軸的值。 // left: 50% 先總體向父容器的左側偏移50%,此時是不能居中的,由於元素自己有大小 // 接着使用transform使用百分比向左偏移自己的寬度的一半實現水平居中(這裏的百分比以元素自己的寬高爲基準) transform:translate(-50%,0); background-color: greenyellow; }複製代碼
margin-left
(元素定寬)
.box { width: 200px; height: 200px; position: relative; background-color: pink; } .box-center { position: absolute; left:50%; height: 100%; // 相似於transform// width: 50%;// margin-left: -25%; width: 100px; margin-left: -50px; background-color: greenyellow; }複製代碼
line-height
等於父元素高度
margin: auto 0
便可(子元素不須要定寬)
display: inline-block, vertical-align: middle
和一個僞元素讓內容塊處於容器中央:
.box { height: 100px; } .box::after, .box-center{ display:inline-block; vertical-align:middle; } .box::after{ content:''; height:100%; }複製代碼
vertical-align
屬性(
vertical-align
只有在父層爲 td 或者 th 時纔會生效,,對於其餘塊級元素,例如 div、p 等,默認狀況是不支持的),爲了使用
vertical-align
,咱們須要設置父元素
display:table
, 子元素
display:table-cell;vertical-align:middle
:
.box { height: 100px; display: table; } .box-center{ display: table-cell; vertical-align:middle; }複製代碼
.box { height: 100px; display: flex; align-items: center; }複製代碼
優勢:內容塊的寬高任意, 優雅的溢出. 可用於更復雜高級的佈局技術中. 缺點:IE8/IE9不支持、須要瀏覽器廠商前綴、渲染上可能會有一些問題。
transform
,設置父元素相對定位:
.box { height: 100px; position: relative; background-color: pink; } .box-center { position: absolute; top: 50%; transform: translate(0, -50%); background-color: greenyellow; }複製代碼
缺點:IE8不支持, 屬性須要追加瀏覽器廠商前綴,可能干擾其餘 transform
效果,某些情形下會出現文本或元素邊界渲染模糊的現象。
.box { position:relative; height: 100px; background-color: pink; } .box-center{ position:absolute; top:50%; // 注意不能使用百分比// margin的百分比計算是相對於父容器的width來計算的,甚至包括margin-top和margin-bottom height: 50px; margin-top: -25px; }複製代碼
.box { position:relative; width: 200px; height: 200px; background-color: pink; } .box-center{ position:absolute; top: 0; bottom: 0; margin: auto 0; height: 100px; background-color: greenyellow; }複製代碼
.box { display: flex; width: 100px; height: 100px; background-color: pink; } .box-center{ margin: auto; background-color: greenyellow; }```css- Flex佈局```css .box { display: flex; width: 100px; height: 100px; background-color: pink; justify-content: center; align-items: center; } .box-center{ background-color: greenyellow; }複製代碼
.box { position: relative; height: 100px; width: 100px; background-color: pink; } .box-center{ position: absolute; left: 0; right: 0; bottom: 0; top: 0; margin: auto; width: 50px; height: 50px; background-color: greenyellow; }複製代碼
小提示:若是在項目中使用過,可簡單介紹一下本身使用Flex解決過什麼問題,這裏我在項目中印象比較深入的是使用Flex解決上面內容高度不固定,下面內容高度自動撐滿父容器剩餘高度的問題。
若是不是很清楚Flex,能夠查看阮一峯的文章Flex 佈局教程:語法篇。面試官追問,那麼除了Flex,你還知道Grid麼?這個因爲兼容性問題,我一直沒有好好研究過,這裏可查看阮一峯的文章CSS Grid網格佈局教程。
小提示:這裏我回答使用函數柯里化加上
apply
或者call
可實現bind
,面試官追問了一些具體的實現細節。
後來我本身粗糙的實現了一下,僅供參考:
Function.prototype.myCall = function (obj) { obj.fn = thislet args = [...arguments].splice(1) let result = obj.fn(...args) delete obj.fn return result } Function.prototype.myApply = function (obj) { obj.fn = thislet args = arguments[1] let result if (args) { result = obj.fn(...args) } else { result = obj.fn() } delete obj.fn return result } Function.prototype.myBind = function (obj) { let context = obj || windowlet _this = thislet _args = [...arguments].splice(1) returnfunction () { let args = arguments// 產生反作用// return obj.fn(..._args, ...args)return _this.apply(context, [..._args, ...args]) } } functionmyFun (argumentA, argumentB) { console.log(this.value) console.log(argumentA) console.log(argumentB) returnthis.value } let obj = { value: 'ziyi2' } console.log(myFun.myCall(obj, 11, 22)) console.log(myFun.myApply(obj, [11, 22])) console.log(myFun.myBind(obj, 33)(11, 22))複製代碼
小提示:這個問題我當時懵了一下,一會兒沒反應過來面試官想要問什麼,就答了這二者在CSS優先級上有區別,而後因爲遇到不會的問題有些緊張就多說了一些廢話,但顯然這不是面試官想要的答案而且消耗了面試官面試的耐心,說他問的不是這個。這裏再次提示你們,若是你感受你說不清楚,可是你又知道一點,我建議你說不知道,不要糾結,面試官不會由於你不知道一個問題就PASS你,相反你說了一些可有可無的廢話,反而在消耗面試官的耐性,增長負面印象。
僞類和僞元素是用來修飾不在文檔樹中的部分,好比,一句話中的第一個字母,或者是列表中的第一個元素。下面分別對僞類和僞元素進行解釋:
僞類用於當已有元素處於的某個狀態時,爲其添加對應的樣式,這個狀態是根據用戶行爲而動態變化的。好比說,當用戶懸停在指定的元素時,咱們能夠經過:hover來描述這個元素的狀態。雖然它和普通的css類類似,能夠爲已有的元素添加樣式,可是它只有處於dom樹沒法描述的狀態下才能爲元素添加樣式,因此將其稱爲僞類。
僞元素用於建立一些不在文檔樹中的元素,併爲其添加樣式。好比說,咱們能夠經過:before來在一個元素前增長一些文本,併爲這些文本添加樣式。雖然用戶能夠看到這些文本,可是這些文本實際上不在文檔樹中。
僞類的操做對象是文檔樹中已有的元素,而僞元素則建立了一個文檔樹外的元素。所以,僞類與僞元素的區別在於:有沒有建立一個文檔樹以外的元素。
CSS3規範中的要求使用雙冒號(::)表示僞元素,以此來區分僞元素和僞類,好比::before和::after等僞元素使用雙冒號(::),:hover和:active等僞類使用單冒號(:)。除了一些低於IE8版本的瀏覽器外,大部分瀏覽器都支持僞元素的雙冒號(::)表示方法。
對於滴滴的此次面試,我感受到本身準備的不是很充分,尤爲是本身簡歷上的項目技術Graphql。同時對於本身不會的題目強行作了一些解釋說明,其實應該簡潔明瞭的告訴面試官不會。
小提示:這裏我說了不少,從借用構造函數到組合繼承到寄生組合繼承,但面試官其實最想聽到的是寄生組合繼承。面試官還追問我具體要如何實現寄生組合繼承。固然這裏其實問的問題還能夠不少,好比ES6的類繼承和ES5中的繼承有什麼區別。
若是對於繼承以及繼承的區別不是很清楚的,能夠隨便看看我以前寫的大筆記js類和繼承。
小提示:這個建議你們好好回憶一下,例如子元素是相對父元素的padding、border仍是content進行定位之類的,當時面試官問的就這麼細。
小提示:面試官只是問了一下具體的使用場景,沒有問實現原理。
functiondebounce (fn, wait = 1000) { let timeOutId returnfunction () { let context = thisif (timeOutId) { clearTimeout(timeOutId) } timeOutId = setTimeout(() => { fn.apply(context, arguments) }, wait) } }複製代碼
functiondebounceImmediate (fn, wait = 1000, immediate) { let timeOutId, context, args const later = (immediate) => setTimeout(() => { if (!immediate) { fn.apply(context, args) timeOutId = context = args = null } }, wait) returnfunction () { if (!timeOutId) { timeOutId = later(true) if (immediate) { fn.apply(this, arguments) } context = this args = arguments } else { clearTimeout(timeOutId) timeOutId = later(false) } } }複製代碼
functionthrottle (fn, wait) { let timeoutId = nullreturnfunction () { let context = thisif (!timeoutId) { timeoutId = setTimeout(() => { fn.apply(context, arguments) timeoutId = null }, wait) } } }複製代碼
小提示:這個問題面試官問的很細,絕對是想問你是否閱讀過源碼。他首先問computed的實現原理,其次問了這樣一個問題:如今有兩個computed計算值,其中一個computed計算值爲何能夠依賴另一個computed計算值。這裏順便將watch的實現原理也貼上。
watch的分類:
watch實現過程:
Object.defineProperty
的設置成響應式)
immediate
屬性那麼立馬執行watch對應的回調函數
var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar' }, computed: { fullName: function () { returnthis.firstName + ' ' + this.lastName } } })複製代碼
因爲 this.firstName
和 this.lastName
(上面是Vue官方示例)都是響應式變量,所以會觸發它們的 getter,根據咱們以前的分析,它們會把自身持有的 dep 添加到當前正在計算的 watcher 中,這個時候Dep.target
就是這個 computed watcher,具體步驟以下:
vm.fullName
的 getter
fullName
計算屬性的值時,Dep 開始依賴收集
firstName
和
lastName
爲
fullName
的依賴,並創建依賴關係
firstName
或
lastName
發生變化時,根據依賴關係,觸發
fullName
的從新計算
經過以上的分析,咱們知道計算屬性本質上就是一個 computed watcher,也瞭解了它的建立過程和被訪問觸發 getter 以及依賴更新的過程,其實這是最新的計算屬性的實現,之因此這麼設計是由於 Vue 想確保不只僅是計算屬性依賴的值發生變化,而是當計算屬性最終計算的值發生變化纔會觸發渲染 watcher 從新渲染,本質上是一種優化。
小提示:這個問題當時徹底不知道,哎,官方源碼的套路太深了......
這裏但願有大神能夠補充說明一下。
)
初始化 data
、props
、computed
、watcher
、provide
。官方源碼具體位置src/core/instance/init.js
:
callHook(vm, 'beforeCreate') initInjections(vm) // resolve injections before data/props initState(vm) initProvide(vm) // resolve provide after data/props callHook(vm, 'created')複製代碼
51信用卡的此次面試其實面試官考察的點仍是蠻深刻的,問了一些Vue底層源碼的實現,整體感受本身回答的還能夠,可是面試官說:你應該去阿里...
小提示:這個直接回答不知道,問題較大,我這裏猜想一下是相似Babel和AST抽象語法樹相關,有空去看下源碼。
這個問題但願同窗能夠補充一下。
小提示:這個問題在回答懶加載的過程當中,面試官追問懶加載的Webpack配置,我說了和代碼切割相關。
關於懶加載,這裏推薦一篇很是好的文章:Webpack 大法之 Code Splitting。
小提示:這個問題實際上是很是常見的問題,建議你們閱讀一下源碼,有些也可能會問一下比較簡單的問題,例如
module.exports
和exports
的區別,或者也可能問CommonJS引入和ES6引入的區別。
小提示:這個問題是個大坑阿,我這裏直接回答我什麼都不擅長,這樣回答顯然面試官是不會不滿意的,建議你們在面試前好好想一想本身到底擅長啥。
小提示:這裏React真的很久沒用了,幾乎忘記了,大體說了下單向數據流、雙向數據綁定、數據監聽方式、JSX以及Vue的單文件組件、函數式編程、Vue的指令之類的。
這個問題但願同時熟悉React和Vue的同窗能夠補充一下。
這個問題但願同窗能夠補充一下。
小提示:面試官這裏應該想問DOM渲染的過程當中可能有哪些狀況會阻塞渲染。我當時回答不知道。
這個問題但願同窗能夠補充一下。
小提示:回答了宏任務和微任務。
小提示:這個問題我專門發了一篇掘金文章,可是不少人好像都不是很感興趣的樣子,可是面試官真的就問了這樣一個問題。
這裏推薦我以前寫的掘金文章基於Vue實現一個簡易MVVM/MV*設計模式的演變歷史,一開始重點講解了MVC、MVP以及MVVM的演變過程和區別。
小提示:真的忘記的差很少了,就簡單說了只能在同一層疊上下文中進行
z-index
值比較、和絕對定位的關係,z-index
值不須要設置過大,只須要理清楚層級關係便可。面試官追問了z-index
值和background
的覆蓋關係,還追問了絕對定位元素以及後來居上的準則。面試官還問了z-index默認值是什麼,0
和auto
有沒有區別?真的對於CSS可能日常就用的很少,因此這個問題答的不是很好。
可能面試官最想知道的是下面這張圖:
這裏附上張鑫旭的文章深刻理解CSS中的層疊上下文和層疊順序。
這裏因爲回答了定位,面試官追問固定定位的元素是相對於什麼進行定位?相對定位會脫離正常文檔流麼?絕對定位是相對於什麼元素進行定位?
小提示:CSS3動畫硬件加速?CSS3動畫的性能問題(重繪和重流,是否須要脫離正常文檔流)?這個我當時答不知道,確實日常用的不多,若是熟悉Vue過渡動畫的同窗能夠講講過渡動畫?
小提示:個人回答:地圖算麼?基於OpenLayers設計過地圖的Vue組件庫。
對於可視化但願同窗能夠補充一下。
小提示:這個問題簡直就是給人挖坑。
這裏簡單實現一下(其實應該使用flex-basis
屬性):
<divclass="box"><divclass="box-left"></div><divclass="box-right"></div></div> .box { height: 200px; display: flex; } .box > div { height: 100%; } .box-left { width: 200px; background-color: blue; } .box-right { flex: 1; // 設置flex-grow屬性爲1,默認爲0 overflow: hidden; background-color: red; }複製代碼
小提示:面試官追問事件委託有什麼優勢(起碼兩個以上)、
target
/currentTarget
/relateTarget
具體指向什麼目標。
小提示:這個若是作過什麼規範或者開發工具之類的,應該比較好回答。
整體來講此次面試面得很細,有些知識點已經忘記,建議你們面試前把一些感受不是很熟悉的原生知識點回憶起來,尤爲是在開發中都不怎麼會使用一些CSS樣式設計的童鞋(如今不少都是組件庫的設計方案,樣式早已經封裝掉了)。
小提示:當時直接回答不知道,確實Webpack我只會用,還沒了解過內部的實現原理和構成。這個後續不管如何都要好好理解一下原理。
這個問題但願同窗能夠補充一下。
小提示:工做中沒有遇到過須要上傳下載大型文件,因此這個問題當時老老實實回答不知道。具體應該和斷點續傳相關,可能也須要回答一些
range
的頭部信息等。
小提示:很久沒用過React了,大體只知道Racct是單向數據流的,利用高階組件能夠實現相似於Vue的雙向數據綁定。
這個問題但願同窗能夠補充一下。
小提示:當時怕說錯,老老實實回答不知道。後來查了一下應該和緩存以及HTTP請求攔截相關。
這個問題但願同窗能夠補充一下。
小提示:只知道上傳的頭信息是
application/x-www-form-urlencoded
,也能夠對上傳的文件的數據進行攔截處理,例如對上傳文件的信息進行加密處理。
這個問題但願同窗能夠補充一下。
其實這一次面試本身感受面試的不是很好(儘管面試官問的確實比我上面列出的問題多),由於有好幾個問題本身確實不清楚。這裏再次建議你們不知道就是回答不知道,這樣不會對面試官形成一些負面印象。這一次面試可以經過運氣佔了很大一部分。
小提示:當時面試官問的蠻好玩的,他問從開始寫一個.vue文件開始到DOM渲染到頁面上,Vue作了哪些工做。而後我當時沒理解面試官是要問vue-loader?DOM樹的渲染過程?來來回回試探性的問了面試官幾回,才理解原來面試官想知道Vue源碼的整個實現過程。
你們若是想了解Vue源碼實現的整個粗略過程,能夠看下以前寫的文章基於Vue實現一個簡易MVVM/Vue的運行機制簡述。
小提示:因爲這邊涉及到一些海康的設備(上下位機通訊),面試官問我如何知道上位機軟件給下位機設備發送了5次信息。這個其實大部分Web前端開發在工做上很難遇到相似的問題,辛虧我之前畢業設計中作過上下位機的TCP通信。後來我從Leader面那裏瞭解到二面面試官應該是作iot物聯網開發這一塊的。
請求幀數據結構以下:
小提示:這個問題當時回答不知道,其實後面想一想最簡單的辦法是先找出廣告元素的一些通用特性,而後在Chrome插件中經過注入腳本的形式將這些廣告元素隱藏掉。
這裏不知道有沒有更好的其餘方式,例如不知道Service Work對請求攔截處理是否能夠有效屏蔽廣告等,這個問題但願同窗能夠補充一下。
小提示:這裏須要分基本類型和引用類型,面試官在這裏具體想問的是
Object.is
的實現原理。這是面試官問個人第一個問題,當時直接回答不知道,心裏都以爲接下來要涼涼了。
小提示:這裏問的是Vue源碼對於視圖更新的優化。我這裏的回答是亂糟糟的,但願有同窗可以給出一個精準而且簡短的回答。
Vue 異步執行 DOM 更新。只要觀察到數據變化,Vue 將開啓一個隊列,並緩衝在同一事件循環中發生的全部數據改變。若是同一個 watcher 被屢次觸發,只會被推入到隊列中一次。這種在緩衝時去除重複數據對於避免沒必要要的計算和 DOM 操做上很是重要。而後,在下一個的事件循環「tick」中,Vue 刷新隊列並執行實際 (已去重的) 工做。Vue 在內部嘗試對異步隊列使用原生的 Promise.then
和 MessageChannel
,若是執行環境不支持,會採用 setTimeout(fn, 0) 代替。
另外,關於waiting
變量,這是很重要的一個標誌位,它保證flushSchedulerQueue
回調($nextTick中執行)容許被置入callbacks
一次。
由於Vue的事件機制是經過事件隊列來調度執行,會等主進程執行空閒後進行調度,因此先會去等待全部的同步代碼執行完成以後再去一次更新。這樣的性能優點很明顯,好比:
如今有這樣的一種狀況,mounted
的時候test
的值會被循環執行++1000次。每次++時,都會根據響應式觸發setter->Dep->Watcher->update->run
。若是這時候沒有異步更新視圖,那麼每次++都會直接操做DOM更新視圖,這是很是消耗性能的。因此Vue實現了一個queue隊列,在下一個tick(或者是當前tick的微任務階段)統一執行queue中Watcher的run。同時,擁有相同id的Watcher不會被重複加入到該queue中去,因此不會執行1000次Watcher的run。最終更新視圖只會直接將test對的DOM的0變成1000。保證更新視圖操做DOM的動做是在當前棧執行完之後下一個tick(或者是當前tick的微任務階段)的時候調用,大大優化了性能。
執行順序update -> queueWatcher -> 維護觀察者隊列(重複id的Watcher處理) -> waiting標誌位處理(保證須要更新DOM或者Watcher視圖更新的方法flushSchedulerQueue只會被推入異步執行的$nextTick回調數組一次) -> 處理$nextTick(在爲微任務或者宏任務中異步更新DOM)->
因爲VUE的數據驅動視圖更新是異步的,即修改數據的當下,視圖不會馬上更新,而是等同一事件循環中的全部數據變化完成以後,再統一進行視圖更新。在同一事件循環中的數據變化後,DOM完成更新,當即執行nextTick(callback)
內的回調。
vue和react同樣,對dom的修改都是異步的。它會在隊列裏記錄你對dom的操做並進行diff操做,後一個操做會覆蓋前一個,而後更新dom。
小提示:我猜這裏面試官想問的是Grid,當時說不知道。
小提示:感謝CBU技術部的面試官。
absolute
或
float
就至關於給元素加上了
display:block
absolute
元素覆蓋正常文檔流內元素(不用設z-index,天然覆蓋)
absolute+ top:-9999em
,或
absolute + visibility:hidden
,將動畫效果放到
absolute
元素中)
static
,默認值。位置設置爲static的元素,它始終會處於文檔流給予的位置。
inherit
,規定應該從父元素繼承 position 屬性的值。可是任何的版本的 Internet Explorer (包括 IE8)都不支持屬性值 「inherit」。
fixed
,生成絕對定位的元素。默認狀況下,可定位於相對於瀏覽器窗口的指定座標。元素的位置經過 「left」, 「top」, 「right」 以及 「bottom」 屬性進行規定。不論窗口滾動與否,元素都會留在那個位置。但當祖先元素具備
transform
屬性且不爲none時,就會相對於祖先元素指定座標,而不是瀏覽器窗口。
absolute
,生成絕對定位的元素,相對於距該元素最近的已定位的祖先元素進行定位。此元素的位置可經過 「left」、」top」、」right」 以及 「bottom」 屬性來規定。
relative
,生成相對定位的元素,相對於該元素在文檔中的初始位置進行定位。經過 「left」、」top」、」right」 以及 「bottom」 屬性來設置此元素相對於自身位置的偏移。
浮動、絕對定位和固定定位會脫離文檔流,相對定位不會脫離文檔流,絕對定位相對於該元素最近的已定位的祖先元素,若是沒有一個祖先元素設置定位,那麼參照物是body層。
絕對定位相對於包含塊的起始位置:
問答題:
這一次面試官問個人第一個問題Object.is
就沒答上來,不過面試官顯然沒有由於開頭答的很差就否認面試者。你們若是在面試時第一個問題就答不上來,不要慌,要保持良好的心態,把接下來能答的問題好好答上來。可能不少同窗會疑問,好像還有好幾個問題感受沒答上來,可是可能只要有一個問題答的很是出彩,仍然能夠彌補那些沒答上來的問題(這裏面試官當時說Vue源碼的實現過程我說的比較清楚,尚未一個面試者答的比我更清楚的)。
三面是Leader現場面,我當時特別擔憂有贊二面的狀況發生,冷不丁又給你來一道算法題,這些真是我最不擅長的點。由於有點心虛我就問了下在阿里的師兄(師兄可能也作招聘工做,當時還怪我沒有找他內推...),他說現場面其實最主要的是好好準備簡歷上的內容,面試官通常都會根據簡歷進行問答,還說他當時面試阿里時會讓他畫一些框架層次圖(這個我當時沒在乎,結果面試官確實讓我根據其中某個項目畫一個框架層次圖)。Leader面的時候在場的有兩個面試官和一個HR。
先是進來一個氣場很足的Leader,看起來很權威,可是問問題還蠻隨意的,就簡單的讓我介紹一下本身作的項目,而後翻看了我作的一些東西。感受他好像有點心不在焉,翻看的很隨意,我在回答問題的時候用餘光關注了一下大佬的表情,感受他在我項目經歷那一塊停留了很是長的時間。
我正回答着本身的項目經歷,Leader二和HR進來了,等我回答完Leader一就讓Leader二開始面我。Leader二就問了我其中的兩個項目。問個人第一個項目是本身作的公司內部的工具,他問這個平臺有什麼能夠衡量的數據代表公司內部人員的使用狀況。我回答當時由於領導以爲不必作,就沒有作數據統計這一塊,告訴了他數據庫裏的一些真實數據狀況。而後他問PV、UV應該怎麼統計(我當時還厚臉皮的問他PV和UV是什麼)?若是訪問的頁面出不來PV怎麼統計?頁面有沒有作什麼行爲監測?頁面訪問量過大怎麼處理?我大體講了一些個人思路。
接着問我第二個項目(Low Code相關),我就回答了這個項目的技術體系,從之前作了什麼到如今作到什麼程度,到將來須要作成什麼樣,通通仔細的說了一遍。Leader二就問我將來作成什麼樣能不能思考一下怎麼作,給了我5分鐘的時間(這期間他一直反覆的在翻閱個人簡歷)。而後我就僞裝思考了5分鐘左右,其實腦子裏一片空白,當時對於將來要作成什麼樣還只是個構思。而後Leader二仍是很體貼的,他說你能夠在牆上畫一畫(牆上能夠寫字),我就大體畫了畫,Leader二問我能不能畫一畫這個項目的框架層次圖,我就簡單的畫了畫...最後Leader二直接說大家作的太Low了,這個(Low Code)在咱們這裏已是兩年前的技術了...(這個我仍是要解釋下,我所在的部門從開始用Vue到目前只有短短的兩年時間,在這兩年時間裏技術體系仍是飛速的在沉澱和發展,我離開以前已經構思並實現了部分Vue技術棧的Low Code解決方案,若是這方面感興趣的同窗也能夠找我溝通)。
Leader二還蠻好玩的,他說Low Code若是真的作出來了,都沒前端什麼事情了,那你幹嗎去?順着這個問題他還問我將來的前端應該怎麼發展?將來前端有哪些能夠挖掘的點?我回答了一些Graphql、可視化等,我還說了一個特別搞笑的回答,我說從以往的發展來看,前端應該搶佔後端的資源,把後端限制咱們的事情讓前端也能作,讓前端更加解放。Leader二當場就進行了反駁,說是要有價值才作,而不是爲了能作而作,嚇得我不輕...而後Leader二還詳細的跟我解釋了將來發展這個問題他但願獲得什麼回答,當時仍是以爲Leader二蠻親切的。
Leader二問完之後HR就接着問我瞭如下幾個問題:
而後Leader一順着HR問了一個小問題:
最後問我還有什麼想問的,我當時已經被三我的問的有點迷迷糊糊了,而後想了想說沒有。
此次現場面其實我感受本身面得不是很好,總感受本身要掛了。總共面了將近1個半小時左右,尤爲是Leader二的問題不少不是他想要的答案,可是最終竟然過了。
企業智能事業部Leader面後又收到了HR面的面試通知,這一輪面試大體問了如下問題:
小提示:這裏HR會問的其實不止這些問題,例如你爲何喜歡Web前端這個崗位、你將來的職業規劃、你以爲你的優勢和缺點有哪些、爲何選擇阿里巴巴、對以前幾個面試官作下評價、你用過阿里的哪些產品順便談談這些產品的優缺點、你對於互聯網是怎麼理解的...
對於HR面仍是要好好準備的,尤爲是有些問題仍是很容易挖坑的,例如你爲何離開如今的公司(你固然不該該抱怨如今的公司有哪些很差的地方,更多的應該代表本身想要尋找更好的發展機會,本身的一些現實因素,好比對於我而言是如今應聘的公司離本身的家更近,又或者是本身工做到達了迷茫期,想跳出迷茫期等等),你以爲你作的最有成就感的一件事(你要是說個簡單的,HR會以爲你工做能力不強),你通常解決問題的方法有哪些(HR固然也想考察你解決問題的能力,你要是說什麼百度啊之類的HR固然會以爲你解決問題的能力不強),你指望的薪資待遇是多少(你要是不喜歡這家公司,能夠指望高一些,你要是很喜歡這家公司面試過程很愉快上浮個30%左右,面試過程通常上浮個20%左右)。