整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          阿里p6前端面經(jīng)(全文3w字)

          阿里p6前端面經(jīng)(全文3w字)

          本文主要給大家?guī)硪恍┪颐嬖嚨慕?jīng)歷和經(jīng)驗,希望對正在求職的同學有所幫助。我先大致說下面試之前的個人情況:2017年7月正式入職海康威視數(shù)字技術股份有限公司,使用Vue.js技術棧。

          我寫的篇幅可能有點長,如果只想看成功的面試請直接從阿里企業(yè)智能事業(yè)部(一面)開始,大家見諒哈。

          關于阿里

          Hi,大家好,我們是阿里巴巴新成立的BU,目前還有大量的Web前端職位空缺,機會難得,希望正在找工作的同學們可以來試試:

          • 目前Web前端急缺P6和P7(阿里的很多BU都只招P7了)
          • 新的BU你進來即是元老
          • 前端技術體系大部分需要一起重新開拓,可以學習到更多的新內(nèi)容
          • 主要負責PC端、客戶端、釘釘E應用以及支付寶小程序的開發(fā)(我本人完全不會小程序,不用擔心)
          • 技術棧是React(如果你是Vue技術棧完全不用擔心,因為我也是)
          • 其他BU面試可能有五輪,我們這邊只有4輪面試

          真的機會難得哦,如果想更多了解我們BU以及找我內(nèi)推的同事加我釘釘或者微信(純粹找我了解或者溝通技術也行,啊哈哈):18768107826

          簡歷

          我的簡歷只是簡單的用MD做了一份,大致包含了以下幾個部分:

          • 基本資料
          • 專業(yè)技能
          • 工作經(jīng)歷
          • 實習經(jīng)歷(可選)
          • 項目經(jīng)歷

          小提示:在基本資料里一定要填寫正確的郵箱地址,我在前期面試的時候都沒有打開郵箱查看面試情況,導致一些面試的時間點和面試結(jié)果都不清楚(一直以為會發(fā)短信通知)。

          如果去現(xiàn)場面試,一定要記得帶上筆和簡歷。一方面你給面試官的簡歷必定是最新的(在不斷面試的過程中你必定會修改簡歷),另一方面這也會給面試官一種非常舒心的感覺。

          對于簡歷這里提一點,在寫自己的專業(yè)技能項目經(jīng)歷時盡量不要給自己挖坑,這里展示一下我的專業(yè)技能(我會的不多):

          • 熟悉嵌入式C、JavaScript、Node.js
          • 熟悉Vue.js框架

          切忌寫一大堆讓人感覺花里胡哨的技能,尤其是一些很淺顯的技能(基本技能除外)。如果你有一些別人很難替代的技能,那這些技能就是亮點了,我這里就沒什么亮點技能。有些技能你會但是不熟練,你可以適當?shù)脑谀愕?strong>項目經(jīng)歷中體現(xiàn)出來。對于項目經(jīng)歷盡量挑自己覺得非常有技術含量的項目進行說明(寧缺毋濫),對于自己參加過但不是特別熟悉的項目盡量不要填寫,防止給自己挖坑。

          小提示:這里附上的我的面試簡歷供大家參考。感謝jsliang的文章2019 面試系列 - 簡歷,大家制作簡歷時也可以參考這篇文章。

          在投遞簡歷時大家千萬不要被招聘信息中的要求嚇到,記得有一次投遞簡歷時我對招聘者說自身不太符合要求,招聘者當時說要求都是唬人的,覺得有興趣就投,有些招聘要求可能正是你未來學習或者深入的領域。

          面試

          簡歷制作完后我大概投了四家公司:有贊、滴滴、51信用卡和阿里。其中有贊掛在二面,滴滴掛在一面,51信用卡掛在一面,阿里兩個部門掛在一面,一個部門面試成功。很多面試者的經(jīng)歷可能都是像我這樣,在一次次的面試失敗中不斷的總結(jié)進步,最終拿到理想的Offer。

          小提示:建議大家在投遞簡歷時可以先投遞一些試水的小公司,先檢驗一下自己是不是可以勝任這些公司的面試。同時在每一次面試完后記得把面試官提問的問題記錄下來,對于沒有答上來的問題還是要好好搞懂或者實踐一下,因為很有可能下一家的面試官會問同樣的問題。

          在面試的過程中,這里我給出幾點意見:

          • 心態(tài)放平穩(wěn),假設第一題你答不上來很正常,面試官不會因為第一題你不會就PASS你
          • 不會的題目一定不要瞎猜,往往面試官給你挖的坑就是希望你往錯的方向猜,一定要答不知道
          • 不要說太多跟當前面試題無關的內(nèi)容,問你什么問題盡量就答什么問題,除非面試官指定你發(fā)散一下思維
          • 如果沒有聽懂面試題可以試著詢問面試官,您要問的是關于xxx的問題么
          • 對于某些問題一定要自己先提前精煉一下(例如作用域鏈、繼承以及原型鏈等問題)
          • 如果面試官問的某項技術自己在某些場景使用過或看到別的場景有使用,可結(jié)合這些場景進行講解(讓面試官知道你不僅僅理解它,你還會很好的使用它)
          • 如果是Vue技術棧希望可以深入源碼或者至少理解一些別人的源碼分析
          • 如果面試阿里那么面試之前一定要好好準備這樣一個問題:你覺得你最擅長什么
          • 面試一定要真誠,切勿投機取巧
          • 面試態(tài)度一定要謙虛

          接下來我會按照面試順序給出面試題以及自己理解的一些答案:

          • 大部分答案都是借鑒別人的博客
          • 有些答案不一定合理
          • 有些答案寫的很零散
          • 有些答案會舉一反三
          • 有些題目太基礎或者重復了就沒有寫答案
          • 有些題目太宏觀或者不知道怎么回答合理,希望大家可以在評論中補充答案供更多的人受益

          有贊(一面)

          說說CSS選擇器以及這些選擇器的優(yōu)先級

          • !important
          • 內(nèi)聯(lián)樣式(1000)
          • ID選擇器(0100)
          • 類選擇器/屬性選擇器/偽類選擇器(0010)
          • 元素選擇器/關系選擇器/偽元素選擇器(0001)
          • 通配符選擇器(0000)

          你知道什么是BFC么

          小提示:這個問題重點是BFC是什么,BFC觸發(fā)的條件有哪些,BFC可以干什么。這里我試著講解了一下Boostrap的清除浮動(display:table創(chuàng)建匿名table-cell間接觸發(fā)BFC),如果有看到別的場景使用或者自身有使用的場景可以嘗試講解一下使用技巧。這樣可以讓面試官覺得你不僅僅知道他問的東西是什么,你還能很好的使用它。

          什么是BFC

          BFC 全稱為塊級格式化上下文 (Block Formatting Context) 。BFC是 W3C CSS 2.1 規(guī)范中的一個概念,它決定了元素如何對其內(nèi)容進行定位以及與其他元素的關系和相互作用,當涉及到可視化布局的時候,Block Formatting Context提供了一個環(huán)境,HTML元素在這個環(huán)境中按照一定規(guī)則進行布局。一個環(huán)境中的元素不會影響到其它環(huán)境中的布局。比如浮動元素會形成BFC,浮動元素內(nèi)部子元素的主要受該浮動元素影響,兩個浮動元素之間是互不影響的。這里有點類似一個BFC就是一個獨立的行政單位的意思。可以說BFC就是一個作用范圍,把它理解成是一個獨立的容器,并且這個容器里box的布局與這個容器外的box毫不相干。

          觸發(fā)BFC的條件

          • 根元素或其它包含它的元素
          • 浮動元素 (元素的 float 不是 none)
          • 絕對定位元素 (元素具有 position 為 absolute 或 fixed)
          • 內(nèi)聯(lián)塊 (元素具有 display: inline-block)
          • 表格單元格 (元素具有 display: table-cell,HTML表格單元格默認屬性)
          • 表格標題 (元素具有 display: table-caption, HTML表格標題默認屬性)
          • 具有overflow 且值不是 visible 的塊元素
          • 彈性盒(flex或inline-flex)
          • display: flow-root
          • column-span: all

          BFC的約束規(guī)則

          • 內(nèi)部的盒會在垂直方向一個接一個排列(可以看作BFC中有一個的常規(guī)流)
          • 處于同一個BFC中的元素相互影響,可能會發(fā)生外邊距重疊
          • 每個元素的margin box的左邊,與容器塊border box的左邊相接觸(對于從左往右的格式化,否則相反),即使存在浮動也是如此
          • BFC就是頁面上的一個隔離的獨立容器,容器里面的子元素不會影響到外面的元素,反之亦然
          • 計算BFC的高度時,考慮BFC所包含的所有元素,連浮動元素也參與計算
          • 浮動盒區(qū)域不疊加到BFC上

          BFC可以解決的問題

          • 垂直外邊距重疊問題
          • 去除浮動
          • 自適用兩列布局(float + overflow)

          了解盒模型么

          包括內(nèi)容區(qū)域內(nèi)邊距區(qū)域邊框區(qū)域外邊距區(qū)域

          box-sizing: content-box(W3C盒子模型):元素的寬高大小表現(xiàn)為內(nèi)容的大小。box-sizing: border-box(IE盒子模型):元素的寬高表現(xiàn)為內(nèi)容 + 內(nèi)邊距 + 邊框的大小。背景會延伸到邊框的外沿。

          IE5.x和IE6在怪異模式中使用非標準的盒子模型,這些瀏覽器的width屬性不是內(nèi)容的寬度,而是內(nèi)容內(nèi)邊距邊框的寬度的總和。

          如何實現(xiàn)左側(cè)寬度固定,右側(cè)寬度自適應的布局

          小提示:這個問題面試官會要求說出幾種解決方法。

          DOM結(jié)構

           <divclass="box"><divclass="box-left"></div><divclass="box-right"></div></div>
          

          利用float + margin實現(xiàn)

           .box {
           height: 200px;
           }
           
           .box > div {
           height: 100%;
           }
           
           .box-left {
           width: 200px;
           float: left;
           background-color: blue;
           }
           
           .box-right {
           margin-left: 200px;
           background-color: red;
           }
          

          利用calc計算寬度

           .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;
           }
          

          利用float + overflow實現(xiàn)

           .box {
           height: 200px;
           }
           
           .box > div {
           height: 100%;
           }
           
           .box-left {
           width: 200px;
           float: left;
           background-color: blue;
           }
           
           .box-right {
           overflow: hidden;
           background-color: red;
           }
          

          利用flex實現(xiàn)

          這里不是最佳答案,應該是使用flex-basis實現(xiàn)更合理

           .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;
           }
          

          了解跨域嗎,一般什么情況下會導致跨域

          小提示:如果平常自身有使用場景可結(jié)合使用場景進行講解,比如我在這里使用過的場景是CORS和Nginx反向代理。

          跨域行為

          • 同源策略限制、安全性考慮
          • 協(xié)議、IP和端口不一致都是跨域行為

          JSONP

          小提示:如果你提到JSONP,面試官肯定會問你整個詳細的實現(xiàn)過程,所以一定要搞懂JSONP的實現(xiàn)原理,如果不是很理解可以自己起一個Express服務實踐一下。

          Web前端事先定義一個用于獲取跨域響應數(shù)據(jù)的回調(diào)函數(shù),并通過沒有同源策略限制的script標簽發(fā)起一個請求(將回調(diào)函數(shù)的名稱放到這個請求的query參數(shù)里),然后服務端返回這個回調(diào)函數(shù)的執(zhí)行,并將需要響應的數(shù)據(jù)放到回調(diào)函數(shù)的參數(shù)里,前端的script標簽請求到這個執(zhí)行的回調(diào)函數(shù)后會立馬執(zhí)行,于是就拿到了執(zhí)行的響應數(shù)據(jù)。

          缺點:JSONP只能發(fā)起GET請求

          如何實現(xiàn)一個JSONP

          這里給出幾個鏈接:

          • https://www.cnblogs.com/iovec/p/5312464.html
          • https://zhangguixu.github.io/2016/12/02/JSONP/
          • https://segmentfault.com/a/1190000015597029

          JSONP安全性問題

          CSRF攻擊

          前端構造一個惡意頁面,請求JSONP接口,收集服務端的敏感信息。如果JSONP接口還涉及一些敏感操作或信息(比如登錄、刪除等操作),那就更不安全了。

          解決方法:驗證JSONP的調(diào)用來源(Referer),服務端判斷Referer是否是白名單,或者部署隨機Token來防御。

          XSS漏洞

          不嚴謹?shù)?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 參數(shù),直接當 html 解析了,就是一個赤裸裸的 XSS 了。

          解決方法:嚴格定義 Content-Type: application/json,然后嚴格過濾 callback 后的參數(shù)并且限制長度(進行字符轉(zhuǎn)義,例如<換成<,>換成>)等,這樣返回的腳本內(nèi)容會變成文本格式,腳本將不會執(zhí)行。

          服務器被黑,返回一串惡意執(zhí)行的代碼

          可以將執(zhí)行的代碼轉(zhuǎn)發(fā)到服務端進行校驗JSONP內(nèi)容校驗,再返回校驗結(jié)果。

          CORS(跨域資款共享)

          小提示:如果你回答跨域解決方案CORS,那么面試官一定會問你實現(xiàn)CORS的響應頭信息Access-Control-Allow-Origin。

          什么是CORS

          CORS(跨域資源共享 Cross-origin resource sharing)允許瀏覽器向跨域服務器發(fā)出XMLHttpRequest請求,從而克服跨域問題,它需要瀏覽器和服務器的同時支持。

          • 瀏覽器端會自動向請求頭添加origin字段,表明當前請求來源。
          • 服務器端需要設置響應頭的Access-Control-Allow-Methods,Access-Control-Allow-Headers,Access-Control-Allow-Origin等字段,指定允許的方法,頭部,源等信息。
          • 請求分為簡單請求和非簡單請求,非簡單請求會先進行一次OPTION方法進行預檢,看是否允許當前跨域請求。

          簡單請求

          請求方法是以下三種方法之一:

          • HEAD
          • GET
          • POST

          HTTP的請求頭信息不超出以下幾種字段:

          • Accept
          • Accept-Language
          • Content-Language
          • Last-Event-ID
          • Content-Type:只限于三個值application/x-www-form-urlencoded、multipart/form-data、text/plain

          后端的響應頭信息:

          • Access-Control-Allow-Origin:該字段是必須的。它的值要么是請求時Origin字段的值,要么是一個*,表示接受任意域名的請求。
          • Access-Control-Allow-Credentials:該字段可選。它的值是一個布爾值,表示是否允許發(fā)送Cookie。
          • Access-Control-Expose-Headers:該字段可選。CORS請求時,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必須在Access-Control-Expose-Headers里面指定。

          非簡單請求

          非簡單請求是那種對服務器有特殊要求的請求,比如請求方法是PUT或DELETE,或者Content-Type字段的類型是application/json。非簡單請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。


          Access-Control-Request-Method:該字段是必須的,用來列出瀏覽器的CORS請求會用到哪些HTTP方法,上例是PUT。


          Access-Control-Request-Headers:該字段是一個逗號分隔的字符串,指定瀏覽器CORS請求會額外發(fā)送的頭信息字段,上例是X-Custom-Header。

          如果瀏覽器否定了"預檢"請求,會返回一個正常的HTTP回應,但是沒有任何CORS相關的頭信息字段。這時,瀏覽器就會認定,服務器不同意預檢請求,因此觸發(fā)一個錯誤,被XMLHttpRequest對象的onerror回調(diào)函數(shù)捕獲。

          JSONP和CORS的對比

          • JSONP只支持GET請求,CORS支持所有類型的HTTP請求
          • JSONP的優(yōu)勢在于支持老式瀏覽器,以及可以向不支持CORS的網(wǎng)站請求數(shù)據(jù)

          其他跨域解決方案

          • Nginx反向代理
          • postMessage
          • document.domain

          HTTP2和HTTP1有什么區(qū)別

          相對于HTTP1.0,HTTP1.1的優(yōu)化:

          • 緩存處理:多了Entity tag,If-Unmodified-Since, If-Match, If-None-Match等緩存信息(HTTTP1.0 If-Modified-Since,Expires)
          • 帶寬優(yōu)化及網(wǎng)絡連接的使用
          • 錯誤通知的管理
          • Host頭處理
          • 長連接:HTTP1.1中默認開啟Connection:keep-alive,一定程度上彌補了HTTP1.0每次請求都要創(chuàng)建連接的缺點。

          相對于HTTP1.1,HTTP2的優(yōu)化:

          • HTTP2支持二進制傳送(實現(xiàn)方便且健壯),HTTP1.x是字符串傳送
          • HTTP2支持多路復用
          • HTTP2采用HPACK壓縮算法壓縮頭部,減小了傳輸?shù)捏w積
          • HTTP2支持服務端推送

          你能說說緩存么

          小提示:如果平常有遇到過緩存的坑或者很好的利用緩存,可以講解一下自己的使用場景。如果沒有使用注意過緩存問題你也可以嘗試講解一下和我們息息相關的Webpack構建(每一次構建靜態(tài)資源名稱的hash值都會變化),它其實就跟緩存相關。有興趣的同學可以查看張云龍的博客大公司里怎樣開發(fā)和部署前端代碼?。

          緩存分為強緩存和協(xié)商緩存。強緩存不過服務器,協(xié)商緩存需要過服務器,協(xié)商緩存返回的狀態(tài)碼是304。兩類緩存機制可以同時存在,強緩存的優(yōu)先級高于協(xié)商緩存。當執(zhí)行強緩存時,如若緩存命中,則直接使用緩存數(shù)據(jù)庫中的數(shù)據(jù),不再進行緩存協(xié)商。

          強緩存

          Expires(HTTP1.0):Exprires的值為服務端返回的數(shù)據(jù)到期時間。當再次請求時的請求時間小于返回的此時間,則直接使用緩存數(shù)據(jù)。但由于服務端時間和客戶端時間可能有誤差,這也將導致緩存命中的誤差。另一方面,Expires是HTTP1.0的產(chǎn)物,故現(xiàn)在大多數(shù)使用Cache-Control替代。

          缺點:使用的是絕對時間,如果服務端和客戶端的時間產(chǎn)生偏差,那么會導致命中緩存產(chǎn)生偏差。

          Pragma(HTTP1.0):HTTP1.0時的遺留字段,當值為"no-cache"時強制驗證緩存,Pragma禁用緩存,如果又給Expires定義一個還未到期的時間,那么Pragma字段的優(yōu)先級會更高。服務端響應添加'Pragma': 'no-cache',瀏覽器表現(xiàn)行為和刷新(F5)類似。

          Cache-Control(HTTP1.1):有很多屬性,不同的屬性代表的意義也不同:

          • private:客戶端可以緩存
          • public:客戶端和代理服務器都可以緩存
          • max-age=t:緩存內(nèi)容將在t秒后失效
          • no-cache:需要使用協(xié)商緩存來驗證緩存數(shù)據(jù)
          • no-store:所有內(nèi)容都不會緩存

          請注意no-cache指令很多人誤以為是不緩存,這是不準確的,no-cache的意思是可以緩存,但每次用應該去想服務器驗證緩存是否可用。no-store才是不緩存內(nèi)容。當在首部字段Cache-Control 有指定 max-age 指令時,比起首部字段 Expires,會優(yōu)先處理 max-age 指令。命中強緩存的表現(xiàn)形式:Firefox瀏覽器表現(xiàn)為一個灰色的200狀態(tài)碼。Chrome瀏覽器狀態(tài)碼表現(xiàn)為200 (from disk cache)或是200 OK (from memory cache)。

          協(xié)商緩存

          協(xié)商緩存需要進行對比判斷是否可以使用緩存。瀏覽器第一次請求數(shù)據(jù)時,服務器會將緩存標識與數(shù)據(jù)一起響應給客戶端,客戶端將它們備份至緩存中。再次請求時,客戶端會將緩存中的標識發(fā)送給服務器,服務器根據(jù)此標識判斷。若未失效,返回304狀態(tài)碼,瀏覽器拿到此狀態(tài)碼就可以直接使用緩存數(shù)據(jù)了。

          Last-Modified:服務器在響應請求時,會告訴瀏覽器資源的最后修改時間。

          if-Modified-Since:瀏覽器再次請求服務器的時候,請求頭會包含此字段,后面跟著在緩存中獲得的最后修改時間。服務端收到此請求頭發(fā)現(xiàn)有if-Modified-Since,則與被請求資源的最后修改時間進行對比,如果一致則返回304和響應報文頭,瀏覽器只需要從緩存中獲取信息即可。

          • 如果真的被修改:那么開始傳輸響應一個整體,服務器返回:200 OK
          • 如果沒有被修改:那么只需傳輸響應header,服務器返回:304 Not Modified

          if-Unmodified-Since: 從某個時間點算起, 是否文件沒有被修改,使用的是相對時間,不需要關心客戶端和服務端的時間偏差。

          • 如果沒有被修改:則開始`繼續(xù)'傳送文件,服務器返回: 200 OK
          • 如果文件被修改:則不傳輸,服務器返回: 412 Precondition failed (預處理錯誤)

          這兩個的區(qū)別是一個是修改了才下載一個是沒修改才下載。如果在服務器上,一個資源被修改了,但其實際內(nèi)容根本沒發(fā)生改變,會因為Last-Modified時間匹配不上而返回了整個實體給客戶端(即使客戶端緩存里有個一模一樣的資源)。為了解決這個問題,HTTP1.1推出了Etag。

          Etag:服務器響應請求時,通過此字段告訴瀏覽器當前資源在服務器生成的唯一標識(生成規(guī)則由服務器決定)

          If-Match:條件請求,攜帶上一次請求中資源的ETag,服務器根據(jù)這個字段判斷文件是否有新的修改

          If-None-Match:再次請求服務器時,瀏覽器的請求報文頭部會包含此字段,后面的值為在緩存中獲取的標識。服務器接收到次報文后發(fā)現(xiàn)If-None-Match則與被請求資源的唯一標識進行對比。

          • 不同,說明資源被改動過,則響應整個資源內(nèi)容,返回狀態(tài)碼200。
          • 相同,說明資源無心修改,則響應header,瀏覽器直接從緩存中獲取數(shù)據(jù)信息。返回狀態(tài)碼304.

          但是實際應用中由于Etag的計算是使用算法來得出的,而算法會占用服務端計算的資源,所有服務端的資源都是寶貴的,所以就很少使用Etag了。

          • 瀏覽器地址欄中寫入URL,回車瀏覽器發(fā)現(xiàn)緩存中有這個文件了,不用繼續(xù)請求了,直接去緩存拿(最快)
          • F5就是告訴瀏覽器,別偷懶,好歹去服務器看看這個文件是否有過期了。于是瀏覽器就膽膽襟襟的發(fā)送一個請求帶上If-Modify-since
          • Ctrl+F5告訴瀏覽器,你先把你緩存中的這個文件給我刪了,然后再去服務器請求個完整的資源文件下來。于是客戶端就完成了強行更新的操作

          緩存場景

          對于大部分的場景都可以使用強緩存配合協(xié)商緩存解決,但是在一些特殊的地方可能需要選擇特殊的緩存策略

          • 對于某些不需要緩存的資源,可以使用 Cache-control: no-store ,表示該資源不需要緩存
          • 對于頻繁變動的資源,可以使用 Cache-Control: no-cache 并配合 ETag 使用,表示該資源已被緩存,但是每次都會發(fā)送請求詢問資源是否更新
          • 對于代碼文件來說,通常使用 Cache-Control: max-age=31536000 并配合策略緩存使用,然后對文件進行指紋處理,一旦文件名變動就會立刻下載新的文件

          能說說首屏加載優(yōu)化有哪些方案么

          小提示:如果做過類似優(yōu)化的同學,可能就比較好回答,沒有做過類似優(yōu)化的同學可以重點講解一下懶加載(當然我這里被面試官追問過懶加載的Webpack配置問題)。同時不知道使用Vue技術棧的同學們有沒有仔細觀察過Vue CLI 3構建的html文件中的link標簽的rel屬性。

          • Vue-Router路由懶加載(利用Webpack的代碼切割)
          • 使用CDN加速,將通用的庫從vendor進行抽離
          • Nginx的gzip壓縮
          • Vue異步組件
          • 服務端渲染SSR
          • 如果使用了一些UI庫,采用按需加載
          • Webpack開啟gzip壓縮
          • 如果首屏為登錄頁,可以做成多入口
          • Service Worker緩存文件處理
          • 使用link標簽的rel屬性設置 prefetch(這段資源將會在未來某個導航或者功能要用到,但是本資源的下載順序權重比較低,prefetch通常用于加速下一次導航)、preload(preload將會把資源得下載順序權重提高,使得關鍵數(shù)據(jù)提前下載好,優(yōu)化頁面打開速度)

          如何在Node端配置路徑別名(類似于Webpack中的alias配置)

          • 全局變量
          • 環(huán)境變量
          • 自己HACK一個@符號,指向特定的路徑
          • HACK require方法

          參考

          這種問題還是附上參考鏈接

          • https://segmentfault.com/a/1190000010998044
          • http://chashaobao.net/2017/09/03/alias-require-hack/
          • https://www.zhihu.com/question/26621212

          談談你對作用域鏈的理解

          小提示:同類型的問題還可以是原型鏈、繼承、閉包等,這種概念性的問題你肯定不是一句兩句能說清楚的,建議在理解之后自己嘗試總結(jié)一下,如何把重要的知識點用簡短的話語說明白。

          了解作用域鏈之前我們要知道一下幾個概念:

          • 函數(shù)的生命周期
          • 變量和函數(shù)的聲明
          • Activetion Object(AO)、Variable Object(VO)

          函數(shù)的生命周期:


          創(chuàng)建:JS解析引擎進行預解析,會將函數(shù)聲明提前,同時將該函數(shù)放到全局作用域中或當前函數(shù)的上一級函數(shù)的局部作用域中。


          執(zhí)行:JS引擎會將當前函數(shù)的局部變量和內(nèi)部函數(shù)進行聲明提前,然后再執(zhí)行業(yè)務代碼,當函數(shù)執(zhí)行完退出時,釋放該函數(shù)的執(zhí)行上下文,并注銷該函數(shù)的局部變量。

          變量和函數(shù)的聲明:如果變量名和函數(shù)名聲明時相同,函數(shù)優(yōu)先聲明。

          Activetion Object(AO)、Variable Object(VO):

          • AO:Activetion Object(活動對象)
          • VO:Variable Object(變量對象)

          VO對應的是函數(shù)創(chuàng)建階段,JS解析引擎進行預解析時,所有的變量和函數(shù)的聲明,統(tǒng)稱為Variable Object。該變量與執(zhí)行上下文相關,知道自己的數(shù)據(jù)存儲在哪里,并且知道如何訪問。VO是一個與執(zhí)行上下文相關的特殊對象,它存儲著在上下文中聲明的以下內(nèi)容:

          • 變量 (var, 變量聲明);
          • 函數(shù)聲明 (FunctionDeclaration, 縮寫為FD);
          • 函數(shù)的形參

          AO對應的是函數(shù)執(zhí)行階段,當函數(shù)被調(diào)用執(zhí)行時,會建立一個執(zhí)行上下文,該執(zhí)行上下文包含了函數(shù)所需的所有變量,該變量共同組成了一個新的對象就是Activetion Object。該對象包含了:

          • 函數(shù)的所有局部變量
          • 函數(shù)的所有命名參數(shù)
          • 函數(shù)的參數(shù)集合
          • 函數(shù)的this指向

          作用域鏈:

          當代碼在一個環(huán)境中創(chuàng)建時,會創(chuàng)建變量對象的一個作用域鏈(scope chain)來保證對執(zhí)行環(huán)境有權訪問的變量和函數(shù)。作用域第一個對象始終是當前執(zhí)行代碼所在環(huán)境的變量對象(VO)。如果是函數(shù)執(zhí)行階段,那么將其activation object(AO)作為作用域鏈第一個對象,第二個對象是上級函數(shù)的執(zhí)行上下文AO,下一個對象依次類推。

          在《JavaScript深入之變量對象》中講到,當查找變量的時候,會先從當前上下文的變量對象中查找,如果沒有找到,就會從父級(詞法層面上的父級)執(zhí)行上下文的變量對象中查找,一直找到全局上下文的變量對象,也就是全局對象。這樣由多個執(zhí)行上下文的變量對象構成的鏈表就叫做作用域鏈。

          你知道null和undefined有什么區(qū)別么

          閉包有什么作用

          Vue響應式原理

          小提示:如果面試者使用的是Vue技術棧,那么響應式原理是一個必問的問題,同時面試官經(jīng)常也會問Vue 3.0在響應式原理上的優(yōu)化方案。

          如果對于響應式原理不是很清楚可以查看我之前寫的文章基于Vue實現(xiàn)一個簡易MVVM/數(shù)據(jù)劫持的實現(xiàn)。

          了解Event Loop么

          小提示:這個題目問到的概率還是蠻大的,這里面試官詢問了我瀏覽器端和Node端的Event Loop有什么不同點。如果想要知道更多瀏覽器端的Event Loop機制可以查看我之前寫的文章你真的理解$nextTick么/JS引擎線程和事件觸發(fā)線程/事件循環(huán)機制。

          事件觸發(fā)線程管理的任務隊列是如何產(chǎn)生的呢?事實上這些任務就是從JS引擎線程本身產(chǎn)生的,主線程在運行時會產(chǎn)生執(zhí)行棧,棧中的代碼調(diào)用某些異步API時會在任務隊列中添加事件,棧中的代碼執(zhí)行完畢后,就會讀取任務隊列中的事件,去執(zhí)行事件對應的回調(diào)函數(shù),如此循環(huán)往復,形成事件循環(huán)機制。JS中有兩種任務類型:微任務(microtask)和宏任務(macrotask),在ES6中,microtask稱為 jobs,macrotask稱為 task:

          • 宏任務:script (主代碼塊)、setTimeout 、setInterval 、setImmediate 、I/O 、UI rendering
          • 微任務:process.nextTick(Nodejs) 、Promise 、Object.observe 、MutationObserver

          Node.js中Event Loop和瀏覽器中Event Loop有什么區(qū)別

           ┌───────────────────────┐
           ┌─>│ timers │<————— 執(zhí)行 setTimeout()、setInterval() 的回調(diào)
           │ └──────────┬────────────┘
           | |<-- 執(zhí)行所有 NextTickQueue 以及 MicroTaskQueue 的回調(diào)
           │ ┌──────────┴────────────┐
           │ │ pendingcallbacks │<————— 執(zhí)行由上一個 Tick 延遲下來的 I/O 回調(diào)(待完善,可忽略)
           │ └──────────┬────────────┘
           | |<-- 執(zhí)行所有 NextTickQueue 以及 MicroTaskQueue 的回調(diào)
           │ ┌──────────┴────────────┐
           │ │ idle, prepare │<————— 內(nèi)部調(diào)用(可忽略)
           │ └──────────┬────────────┘
           | |<-- 執(zhí)行所有 NextTickQueue 以及 MicroTaskQueue 的回調(diào)
           | | ┌───────────────┐
           │ ┌──────────┴────────────┐ │ incoming: │ - (執(zhí)行幾乎所有的回調(diào),除了 closecallbacks、timers、setImmediate)
           │ │ poll │<─────┤ connections, │
           │ └──────────┬────────────┘ │ data, etc. │
           │ | | |
           | | └───────────────┘
           | |<-- 執(zhí)行所有 NextTickQueue 以及 MicroTaskQueue 的回調(diào)
           | ┌──────────┴────────────┐
           │ │ check │<————— setImmediate() 的回調(diào)將會在這個階段執(zhí)行
           │ └──────────┬────────────┘
           | |<-- 執(zhí)行所有 NextTickQueue 以及 MicroTaskQueue 的回調(diào)
           │ ┌──────────┴────────────┐
           └──┤ closecallbacks │<————— socket.on('close', ...)
           └───────────────────────┘
          

          Node.js中宏任務分成了幾種類型,并且放在了不同的task queue里。不同的task queue在執(zhí)行順序上也有區(qū)別,微任務放在了每個task queue的末尾:

          • setTimeout/setInterval 屬于 timers 類型;
          • setImmediate 屬于 check 類型;
          • socket 的 close 事件屬于 close callbacks 類型;
          • 其他 MacroTask 都屬于 poll 類型。
          • process.nextTick 本質(zhì)上屬于 MicroTask,但是它先于所有其他 MicroTask 執(zhí)行;
          • 所有 MicroTask 的執(zhí)行時機在不同類型的 MacroTask 切換后。
          • idle/prepare 僅供內(nèi)部調(diào)用,我們可以忽略。
          • pending callbacks 不太常見,我們也可以忽略。

          如何避免回流和重繪

          瀏覽器渲染過程

          • 瀏覽器使用流式布局模型 (Flow Based Layout)
          • 瀏覽器會把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就產(chǎn)生了Render Tree
          • 有了RenderTree就能知道所有節(jié)點的樣式,計算節(jié)點在頁面上的大小和位置,把節(jié)點繪制到頁面上
          • 由于瀏覽器使用流式布局,對Render Tree的計算通常只需要遍歷一次就可以完成,但table及其內(nèi)部元素除外,通常需要多次計算且要花費3倍于同等元素的時間,這也是為什么要避免使用table布局的原因之一

          瀏覽器渲染過程如下:

          • 解析HTML,生成DOM樹
          • 解析CSS,生成CSSOM樹
          • 將DOM樹和CSSOM樹結(jié)合,生成渲染樹(Render Tree)
          • Layout(回流):根據(jù)生成的渲染樹,進行回流(Layout),得到節(jié)點的幾何信息(位置,大小)
          • Painting(重繪):根據(jù)渲染樹以及回流得到的幾何信息,得到節(jié)點的絕對像素
          • Display:將像素發(fā)送給GPU,展示在頁面上。(這一步其實還有很多內(nèi)容,比如會在GPU將多個合成層合并為同一個層,并展示在頁面中。而css3硬件加速的原理則是新建合成層,這里我們不展開,之后有機會會寫一篇博客)

          何時觸發(fā)回流和重繪

          何時發(fā)生回流:

          • 添加或刪除可見的DOM元素
          • 元素的位置發(fā)生變化
          • 元素的尺寸發(fā)生變化(包括外邊距、內(nèi)邊框、邊框大小、高度和寬度等)
          • 內(nèi)容發(fā)生變化,比如文本變化或圖片被另一個不同尺寸的圖片所替代。
          • 頁面一開始渲染的時候(這肯定避免不了)
          • 瀏覽器的窗口尺寸變化(因為回流是根據(jù)視口的大小來計算元素的位置和大小的)

          何時發(fā)生重繪(回流一定會觸發(fā)重繪):

          當頁面中元素樣式的改變并不影響它在文檔流中的位置時(例如:color、background-color、visibility等),瀏覽器會將新樣式賦予給元素并重新繪制它,這個過程稱為重繪。

          有時即使僅僅回流一個單一的元素,它的父元素以及任何跟隨它的元素也會產(chǎn)生回流。現(xiàn)代瀏覽器會對頻繁的回流或重繪操作進行優(yōu)化,瀏覽器會維護一個隊列,把所有引起回流和重繪的操作放入隊列中,如果隊列中的任務數(shù)量或者時間間隔達到一個閾值的,瀏覽器就會將隊列清空,進行一次批處理,這樣可以把多次回流和重繪變成一次。你訪問以下屬性或方法時,瀏覽器會立刻清空隊列:

          • clientWidth、clientHeight、clientTop、clientLeft
          • offsetWidth、offsetHeight、offsetTop、offsetLeft
          • scrollWidth、scrollHeight、scrollTop、scrollLeft
          • width、height
          • getComputedStyle()
          • getBoundingClientRect()

          以上屬性和方法都需要返回最新的布局信息,因此瀏覽器不得不清空隊列,觸發(fā)回流重繪來返回正確的值。因此,我們在修改樣式的時候,**最好避免使用上面列出的屬性,他們都會刷新渲染隊列。**如果要使用它們,最好將值緩存起來。

          如何避免觸發(fā)回流和重繪

          CSS:

          • 避免使用table布局。
          • 盡可能在DOM樹的最末端改變class。
          • 避免設置多層內(nèi)聯(lián)樣式。
          • 將動畫效果應用到position屬性為absolute或fixed的元素上
          • 避免使用CSS表達式(例如:calc())
          • CSS3硬件加速(GPU加速)

          JavaScript:

          • 避免頻繁操作樣式,最好一次性重寫style屬性,或者將樣式列表定義為class并一次性更改class屬性
          • 避免頻繁操作DOM,創(chuàng)建一個documentFragment,在它上面應用所有DOM操作,最后再把它添加到文檔中
          • 也可以先為元素設置display: none,操作結(jié)束后再把它顯示出來。因為在display屬性為none的元素上進行的DOM操作不會引發(fā)回流和重繪
          • 避免頻繁讀取會引發(fā)回流/重繪的屬性,如果確實需要多次使用,就用一個變量緩存起來
          • 對具有復雜動畫的元素使用絕對定位,使它脫離文檔流,否則會引起父元素及后續(xù)元素頻繁回流

          有贊(二面)

          小提示:進入現(xiàn)場面試需要注意好好準備自己的簡歷,面試官一般會根據(jù)項目進行問答。

          筆試題環(huán)節(jié)

          一開始面試官就發(fā)了兩張筆試題試卷,總共四道題目,大致考了以下知識點:

          • 作用域
          • 原型鏈(例如實例屬性和原型屬性一樣,刪除實例屬性后可以繼續(xù)訪問原型屬性問題)
          • 宏任務和微任務的打印順序
          • Array.prototype.map的第二個參數(shù)

          項目問答環(huán)節(jié)

          答完試卷面試官就開始問簡歷上的一些項目,我記得其中幾個問題如下(事實上他問的一些問題和簡歷不是很相關):

          • 你們產(chǎn)品的服務器部署在哪里
          • 你是如何實現(xiàn)一個Tooltip組件的,能寫一下怎么使用這個組件么(這算什么問題...)
          • 我認識你們海康的一些開發(fā),我知道你們的產(chǎn)品按套數(shù)賣的...

          我當場就感受到了面試官問的問題很敷衍,可能他覺得我的簡歷不夠好,又或者覺得我能力不行,接下來面試官又讓我做了一道算法題...

          算法題環(huán)節(jié)

          • 1塊、4塊、5塊,求總數(shù)n塊的最小硬幣數(shù)

          當時沒做出來,非科班出身可能做這些確實有些困難,也沒有系統(tǒng)的學習,面試官看我很困難的樣子,就換了一道題。

          • 1、1、2、3、5、8...計算第n個數(shù)的值(斐波那契數(shù)列)

          這道題還是做出來了,畢竟比較簡單,然后面試官說今天先到這里,面試結(jié)果會在一星期內(nèi)通知,然后回來的那天晚上就收到了面試沒過的通知。

          小結(jié)

          還是蠻感謝這次現(xiàn)場面試的經(jīng)歷,讓我知道如果自身不夠硬,到哪里都會很被動。面試的好處不僅僅在于檢驗自己到底有多少能力,更應該發(fā)現(xiàn)自身的不足,同時不斷的去彌補這些不足。于是我再次捧起之前擱置的《算法導論》,并且創(chuàng)建了一個算法學習演示文檔I-Algorithms,希望可以簡化《算法導論》的一些理論知識,使大家對于算法的學習可以變得更加系統(tǒng)全面和簡單,也希望通過這個學習使得算法面試會變得更加得心應手,希望感興趣的同學可以star一下。

          滴滴(一面)

          你知道哪些安全問題,如何避免

          小提示:這里我簡單講解了一下Vue中的v-html防范XSS攻擊。

          XSS(跨站腳本攻擊)

          XSS,即 Cross Site Script,中譯是跨站腳本攻擊;其原本縮寫是 CSS,但為了和層疊樣式表(Cascading Style Sheet)有所區(qū)分,因而在安全領域叫做 XSS。

          XSS 攻擊是指攻擊者在網(wǎng)站上注入惡意的客戶端代碼,通過惡意腳本對客戶端網(wǎng)頁進行篡改,從而在用戶瀏覽網(wǎng)頁時,對用戶瀏覽器進行控制或者獲取用戶隱私數(shù)據(jù)的一種攻擊方式。

          攻擊者對客戶端網(wǎng)頁注入的惡意腳本一般包括 JavaScript,有時也會包含 HTML 和 Flash。有很多種方式進行 XSS 攻擊,但它們的共同點為:將一些隱私數(shù)據(jù)像 cookie、session 發(fā)送給攻擊者,將受害者重定向到一個由攻擊者控制的網(wǎng)站,在受害者的機器上進行一些惡意操作。

          XSS攻擊可以分為3類:反射型(非持久型)、存儲型(持久型)、基于DOM。

          反射型

          反射型 XSS 只是簡單地把用戶輸入的數(shù)據(jù) “反射” 給瀏覽器,這種攻擊方式往往需要攻擊者誘使用戶點擊一個惡意鏈接(攻擊者可以將惡意鏈接直接發(fā)送給受信任用戶,發(fā)送的方式有很多種,比如 email, 網(wǎng)站的私信、評論等,攻擊者可以購買存在漏洞網(wǎng)站的廣告,將惡意鏈接插入在廣告的鏈接中),或者提交一個表單,或者進入一個惡意網(wǎng)站時,注入腳本進入被攻擊者的網(wǎng)站。最簡單的示例是訪問一個鏈接,服務端返回一個可執(zhí)行腳本:

           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 會把用戶輸入的數(shù)據(jù) "存儲" 在服務器端,當瀏覽器請求數(shù)據(jù)時,腳本從服務器上傳回并執(zhí)行。這種 XSS 攻擊具有很強的穩(wěn)定性。比較常見的一個場景是攻擊者在社區(qū)或論壇上寫下一篇包含惡意 JavaScript 代碼的文章或評論,文章或評論發(fā)表后,所有訪問該文章或評論的用戶,都會在他們的瀏覽器中執(zhí)行這段惡意的 JavaScript 代碼:

           // 例如在評論中輸入以下留言
           // 如果請求這段留言的時候服務端不做轉(zhuǎn)義處理,請求之后頁面會執(zhí)行這段惡意代碼
           <script>alert('xss 攻擊')</script>
          

          基于DOM

          基于 DOM 的 XSS 攻擊是指通過惡意腳本修改頁面的 DOM 結(jié)構,是純粹發(fā)生在客戶端的攻擊:

           <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 按鈕后,會在當前頁面插入一個鏈接,其地址為用戶的輸入內(nèi)容。如果用戶在輸入時構造了如下內(nèi)容:

           onclick=alert(/xss/)
          

          用戶提交之后,頁面代碼就變成了:

           <a href onlick="alert(/xss/)">testLink</a>
          

          此時,用戶點擊生成的鏈接,就會執(zhí)行對應的腳本。

          XSS攻擊防范

          HttpOnly 防止劫取 Cookie:HttpOnly 最早由微軟提出,至今已經(jīng)成為一個標準。瀏覽器將禁止頁面的Javascript 訪問帶有 HttpOnly 屬性的Cookie。上文有說到,攻擊者可以通過注入惡意腳本獲取用戶的 Cookie 信息。通常 Cookie 中都包含了用戶的登錄憑證信息,攻擊者在獲取到 Cookie 之后,則可以發(fā)起 Cookie 劫持攻擊。所以,嚴格來說,HttpOnly 并非阻止 XSS 攻擊,而是能阻止 XSS 攻擊后的 Cookie 劫持攻擊。

          輸入檢查:不要相信用戶的任何輸入。對于用戶的任何輸入要進行檢查、過濾和轉(zhuǎn)義。建立可信任的字符和 HTML 標簽白名單,對于不在白名單之列的字符或者標簽進行過濾或編碼。在 XSS 防御中,輸入檢查一般是檢查用戶輸入的數(shù)據(jù)中是否包含 <,> 等特殊字符,如果存在,則對特殊字符進行過濾或編碼,這種方式也稱為 XSS Filter。而在一些前端框架中,都會有一份 decodingMap, 用于對用戶輸入所包含的特殊字符或標簽進行編碼或過濾,如 <,>,script,防止 XSS 攻擊:

           // vuejs 中的 decodingMap// 在 vuejs 中,如果輸入帶 script 標簽的內(nèi)容,會直接過濾掉const decodingMap={
           '<': '<',
           '>': '>',
           '"': '"',
           '&': '&',
           '
          ': '\n'
           }
          

          輸出檢查:用戶的輸入會存在問題,服務端的輸出也會存在問題。一般來說,除富文本的輸出外,在變量輸出到 HTML 頁面時,可以使用編碼或轉(zhuǎn)義的方式來防御 XSS 攻擊。例如利用 sanitize-html 對輸出內(nèi)容進行有規(guī)則的過濾之后再輸出到頁面中。

          CSRF/XSRF(跨站請求偽造)

          CSRF,即 Cross Site Request Forgery,中譯是跨站請求偽造,是一種劫持受信任用戶向服務器發(fā)送非預期請求的攻擊方式。通常情況下,CSRF 攻擊是攻擊者借助受害者的 Cookie 騙取服務器的信任,可以在受害者毫不知情的情況下以受害者名義偽造請求發(fā)送給受攻擊服務器,從而在并未授權的情況下執(zhí)行在權限保護之下的操作。

          Cookie

          Cookie 是服務器發(fā)送到用戶瀏覽器并保存在本地的一小塊數(shù)據(jù),它會在瀏覽器下次向同一服務器再發(fā)起請求時被攜帶并發(fā)送到服務器上。Cookie 主要用于以下三個方面:

          • 會話狀態(tài)管理(如用戶登錄狀態(tài)、購物車、游戲分數(shù)或其它需要記錄的信息)
          • 個性化設置(如用戶自定義設置、主題等)
          • 瀏覽器行為跟蹤(如跟蹤分析用戶行為等)

          而瀏覽器所持有的 Cookie 分為兩種:

          • Session Cookie(會話期 Cookie):會話期 Cookie 是最簡單的Cookie,它不需要指定過期時間(Expires)或者有效期(Max-Age),它僅在會話期內(nèi)有效,瀏覽器關閉之后它會被自動刪除。
          • Permanent Cookie(持久性 Cookie):與會話期 Cookie 不同的是,持久性 Cookie 可以指定一個特定的過期時間(Expires)或有效期(Max-Age)。
           res.setHeader('Set-Cookie', ['mycookie=222', 'test=3333; expires=Sat, 21 Jul 2018 00:00:00 GMT;']);
          

          上述代碼創(chuàng)建了兩個 Cookie:mycookie 和 test,前者屬于會話期 Cookie,后者則屬于持久性 Cookie。

          CSRF攻擊

          使登錄用戶訪問攻擊者的網(wǎng)站,發(fā)起一個請求,由于 Cookie 中包含了用戶的認證信息,當用戶訪問攻擊者準備的攻擊環(huán)境時,攻擊者就可以對服務器發(fā)起 CSRF 攻擊。

          在這個攻擊過程中,攻擊者借助受害者的 Cookie 騙取服務器的信任,但并不能拿到 Cookie,也看不到 Cookie 的內(nèi)容。而對于服務器返回的結(jié)果,由于瀏覽器同源策略的限制,攻擊者也無法進行解析。(攻擊者的網(wǎng)站雖然是跨域的,但是他構造的鏈接是源網(wǎng)站的,跟源網(wǎng)站是同源的,所以能夠攜帶cookie發(fā)起訪問)。

          但是攻擊者無法從返回的結(jié)果中得到任何東西,他所能做的就是給服務器發(fā)送請求,以執(zhí)行請求中所描述的命令,在服務器端直接改變數(shù)據(jù)的值,而非竊取服務器中的數(shù)據(jù)。例如刪除數(shù)據(jù)、修改數(shù)據(jù),新增數(shù)據(jù)等,無法獲取數(shù)據(jù)。

          CSRF攻擊防范

          驗證碼:驗證碼被認為是對抗 CSRF 攻擊最簡潔而有效的防御方法。從上述示例中可以看出,CSRF 攻擊往往是在用戶不知情的情況下構造了網(wǎng)絡請求。而驗證碼會強制用戶必須與應用進行交互,才能完成最終請求。因為通常情況下,驗證碼能夠很好地遏制 CSRF 攻擊。但驗證碼并不是萬能的,因為出于用戶考慮,不能給網(wǎng)站所有的操作都加上驗證碼。因此,驗證碼只能作為防御 CSRF 的一種輔助手段,而不能作為最主要的解決方案。

          Referer Check:根據(jù) HTTP 協(xié)議,在 HTTP 頭中有一個字段叫 Referer,它記錄了該 HTTP 請求的來源地址。通過 Referer Check,可以檢查請求是否來自合法的"源"。

          添加token驗證:要抵御 CSRF,關鍵在于在請求中放入攻擊者所不能偽造的信息,并且該信息不存在于 Cookie 之中。可以在 HTTP 請求中以參數(shù)的形式加入一個隨機產(chǎn)生的 token,并在服務器端建立一個攔截器來驗證這個 token,如果請求中沒有 token 或者 token 內(nèi)容不正確,則認為可能是 CSRF 攻擊而拒絕該請求。

          介紹一下Graphql

          小提示:這道題是給自己挖了一個坑,抱著學習的心態(tài)嘗試使用Graphql技術,卻沒有好好理解是在什么場景下為了解決什么問題才應該使用,也沒有好好準備如何描述新技術,往往這種不熟悉的技術自己在簡歷中應該留存一些心眼,盡量不要提,否則答不上來會很尷尬,讓面試官懷疑你的項目成分。

          什么是Graphql

          GraphQL是一種API查詢語言。API接口的返回值可以從靜態(tài)變?yōu)閯討B(tài),即調(diào)用者來聲明接口返回什么數(shù)據(jù),可以進一步解耦前后端。在Graphal中,預先定義Schema和聲明Type來達到動態(tài)獲取接口數(shù)據(jù)的目的:

          • 對于數(shù)據(jù)模型的抽象是通過Type來描述的
          • 對于接口獲取數(shù)據(jù)的邏輯是通過Schema來描述的

          為什么要使用Graphql:

          • 接口數(shù)量眾多維護成本高
          • 接口擴展成本高
          • 接口響應的數(shù)據(jù)格式無法預知
          • 減少無用數(shù)據(jù)的請求, 按需獲取
          • 強類型約束(API的數(shù)據(jù)格式讓前端來定義,而不是后端定義)

          Type(數(shù)據(jù)模型的抽象)

          Type簡單可以分為兩種,一種叫做Scalar Type(標量類型),另一種叫做Object Type(對象類型):


          Scalar Type(標量類型):內(nèi)建的標量包含,String、Int、Float、Boolean、Enum


          Object Type(對象類型):感覺類似于TypeScript的接口類型


          Type Modifier(類型修飾符):用于表明是否必填等

          Schema(模式)

          定義了字段的類型、數(shù)據(jù)的結(jié)構,描述了接口數(shù)據(jù)請求的規(guī)則

          Query(查詢、操作類型)

          查詢類型:query(查詢)、mutation(更改)和subscription(訂閱)

          • query(查詢):當獲取數(shù)據(jù)時,應當選取Query類型
          • mutation(更改):當嘗試修改數(shù)據(jù)時,應當使用mutation類型
          • subscription(訂閱):當希望數(shù)據(jù)更改時,可以進行消息推送,使用subscription類型

          Resolver(解析函數(shù))

          提供相關Query所返回數(shù)據(jù)的邏輯。Query和與之對應的Resolver是同名的,這樣在GraphQL才能把它們對應起來。解析的過程可能是遞歸的,只要遇到非標量類型,會嘗試繼續(xù)解析,如果遇到標量類型,那么解析完成,這個過程叫做解析鏈。

          說說Vue中$nextTick的實現(xiàn)原理

          小提示:如果面試者使用的是Vue技術棧,那么$nextTick的原理是一個高頻問題,面試者借此可以追問的東西較多,例如瀏覽器的Event Loop、微任務和宏任務、Node.js的Event Loop、異步更新DOM(響應式的數(shù)據(jù)for循環(huán)改變了1000次為什么視圖只更新了一次)、$nextTick歷史版本問題等等。

          這個如果不是很清楚的具體可查看我之前寫的文章你真的理解$nextTick么。

          Vue響應式原理

          談談對閉包的理解

          JSONP的實現(xiàn)原理

          CSS中的BFC

          如何實現(xiàn)居中

          水平居中

          • 若是行內(nèi)元素,給其父元素設置text-align:center即可實現(xiàn)行內(nèi)元素水平居中
          • 若是塊級元素,該元素設置margin:0 auto即可(元素需要定寬)
          • 若是塊級元素,設置父元素為flex布局,子元素設置margin:0 auto即可(子元素不需要定寬)
          • 使用flex 2012年版本布局,可以輕松的實現(xiàn)水平居中,子元素設置如下:
           // flex容器
           <div class="box">
           // flex項目
           <div class="box-center">
           </div>
           </div>
           
           
           .box {
           width: 200px;
           height: 200px;
           display: flex;
           // 使內(nèi)部的flex項目水平居中
           justify-content: center;
           background-color: pink;
           }
           
           /* .box-center {
           width: 50%;
           background-color: greenyellow;
           } */
           
           
          
          • 使用絕對定位和CSS3新增的屬性transform(這個屬性還和GPU硬件加速、固定定位相關)
           .box {
           width: 200px;
           height: 200px;
           position: relative;
           background-color: pink;
           }
           
           .box-center {
           position: absolute;
           left:50%;
           // width: 50%;
           height: 100%;
           // 通過 translate() 方法,元素從其當前位置移動,根據(jù)給定的 left(x 坐標) 和 top(y 坐標) 位置參數(shù):
           // translate(x,y)	定義 2D 轉(zhuǎn)換。
           // translateX(x)	定義轉(zhuǎn)換,只是用 X 軸的值。
           // translateY(y)	定義轉(zhuǎn)換,只是用 Y 軸的值。
           // left: 50% 先整體向父容器的左側(cè)偏移50%,此時是不能居中的,因為元素本身有大小
           // 接著使用transform使用百分比向左偏移本身的寬度的一半實現(xiàn)水平居中(這里的百分比以元素本身的寬高為基準)
           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等于父元素高度
          • 若是塊級元素,設置父元素為flex布局,子元素設置margin: auto 0即可(子元素不需要定寬)
          • 若元素是行內(nèi)塊級元素,基本思想是使用display: inline-block, vertical-align: middle和一個偽元素讓內(nèi)容塊處于容器中央:
           .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;
           }
          
          • 可用 Flex 2012版, 這是CSS布局未來的趨勢。Flexbox是CSS3新增屬性,設計初衷是為了解決像垂直居中這樣的常見布局問題:
           .box {
           height: 100px;
           display: flex;
           align-items: center;
           }
          

          優(yōu)點:內(nèi)容塊的寬高任意, 優(yōu)雅的溢出. 可用于更復雜高級的布局技術中. 缺點: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 效果,某些情形下會出現(xiàn)文本或元素邊界渲染模糊的現(xiàn)象。

          居中元素高度固定

          • 設置父元素相對定位,子元素如下css樣式:
           
           .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;
           }
          
          • 設置父元素相對定位, 子元素如下css樣式:
           .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;
           }
          

          水平垂直居中

          • Flex布局(子元素是塊級元素)
           .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;
           }
          
          • 絕對定位實現(xiàn)(定位元素定寬定高)
           .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解決上面內(nèi)容高度不固定,下面內(nèi)容高度自動撐滿父容器剩余高度的問題。

          如果不是很清楚Flex,可以查看阮一峰的文章Flex 布局教程:語法篇。面試官追問,那么除了Flex,你還知道Grid么?這個由于兼容性問題,我一直沒有好好研究過,這里可查看阮一峰的文章CSS Grid網(wǎng)格布局教程。

          bind的源碼實現(xiàn)

          小提示:這里我回答使用函數(shù)柯里化加上apply或者call可實現(xiàn)bind,面試官追問了一些具體的實現(xiàn)細節(jié)。

          后來我自己粗糙的實現(xiàn)了一下,僅供參考:

           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// 產(chǎn)生副作用// 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))
          

          偽類和偽元素的區(qū)別

          小提示:這個問題我當時懵了一下,一下子沒反應過來面試官想要問什么,就答了這兩者在CSS優(yōu)先級上有區(qū)別,然后由于遇到不會的問題有些緊張就多說了一些廢話,但顯然這不是面試官想要的答案并且消耗了面試官面試的耐心,說他問的不是這個。這里再次提示大家,如果你感覺你說不清楚,但是你又知道一點,我建議你說不知道,不要糾結(jié),面試官不會因為你不知道一個問題就PASS你,相反你說了一些無關緊要的廢話,反而在消耗面試官的耐性,增加負面印象。

          偽類和偽元素是用來修飾不在文檔樹中的部分,比如,一句話中的第一個字母,或者是列表中的第一個元素。下面分別對偽類和偽元素進行解釋:

          偽類用于當已有元素處于的某個狀態(tài)時,為其添加對應的樣式,這個狀態(tài)是根據(jù)用戶行為而動態(tài)變化的。比如說,當用戶懸停在指定的元素時,我們可以通過:hover來描述這個元素的狀態(tài)。雖然它和普通的css類相似,可以為已有的元素添加樣式,但是它只有處于dom樹無法描述的狀態(tài)下才能為元素添加樣式,所以將其稱為偽類。

          偽元素用于創(chuàng)建一些不在文檔樹中的元素,并為其添加樣式。比如說,我們可以通過:before來在一個元素前增加一些文本,并為這些文本添加樣式。雖然用戶可以看到這些文本,但是這些文本實際上不在文檔樹中。

          區(qū)別

          偽類的操作對象是文檔樹中已有的元素,而偽元素則創(chuàng)建了一個文檔樹外的元素。因此,偽類與偽元素的區(qū)別在于:有沒有創(chuàng)建一個文檔樹之外的元素。

          CSS3規(guī)范中的要求使用雙冒號(::)表示偽元素,以此來區(qū)分偽元素和偽類,比如::before和::after等偽元素使用雙冒號(::),:hover和:active等偽類使用單冒號(:)。除了一些低于IE8版本的瀏覽器外,大部分瀏覽器都支持偽元素的雙冒號(::)表示方法。

          小結(jié)

          對于滴滴的這次面試,我感覺到自己準備的不是很充分,尤其是自己簡歷上的項目技術Graphql。同時對于自己不會的題目強行做了一些解釋說明,其實應該簡潔明了的告訴面試官不會。

          51信用卡(一面)

          說說DOM事件流

          在ES5中如何實現(xiàn)繼承

          小提示:這里我說了很多,從借用構造函數(shù)到組合繼承到寄生組合繼承,但面試官其實最想聽到的是寄生組合繼承。面試官還追問我具體要如何實現(xiàn)寄生組合繼承。當然這里其實問的問題還可以很多,比如ES6的類繼承和ES5中的繼承有什么區(qū)別。

          如果對于繼承以及繼承的區(qū)別不是很清楚的,可以隨便看看我之前寫的大筆記js類和繼承。

          絕對定位

          小提示:這個建議大家好好回憶一下,例如子元素是相對父元素的padding、border還是content進行定位之類的,當時面試官問的就這么細。

          消抖和節(jié)流

          小提示:面試官只是問了一下具體的使用場景,沒有問實現(xiàn)原理。

          簡單消抖

           functiondebounce (fn, wait=1000) {
           let timeOutId
           
           returnfunction () {
           let context=thisif (timeOutId) {
           clearTimeout(timeOutId)
           }
           
           timeOutId=setTimeout(()=> {
           fn.apply(context, arguments)
           }, wait)
           }
           }
          

          帶立即執(zhí)行參數(shù)的消抖

           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)
           }
           }
           }
          

          節(jié)流

           functionthrottle (fn, wait) {
           let timeoutId=nullreturnfunction () {
           let context=thisif (!timeoutId) {
           timeoutId=setTimeout(()=> {
           fn.apply(context, arguments)
           timeoutId=null
           }, wait)
           }
           }
           }
          

          Vue中的computed實現(xiàn)原理

          小提示:這個問題面試官問的很細,絕對是想問你是否閱讀過源碼。他首先問computed的實現(xiàn)原理,其次問了這樣一個問題:現(xiàn)在有兩個computed計算值,其中一個computed計算值為什么可以依賴另外一個computed計算值。這里順便將watch的實現(xiàn)原理也貼上。

          watch的實現(xiàn)原理

          watch的分類:

          • deep watch(深層次監(jiān)聽)
          • user watch(用戶監(jiān)聽)
          • computed watcher(計算屬性)
          • sync watcher(同步監(jiān)聽)

          watch實現(xiàn)過程:

          • watch的初始化在data初始化之后(此時的data已經(jīng)通過Object.defineProperty的設置成響應式)
          • watch的key會在Watcher里進行值的讀取,也就是立馬執(zhí)行get獲取value(從而實現(xiàn)data對應的key執(zhí)行getter實現(xiàn)對于watch的依賴收集),此時如果有immediate屬性那么立馬執(zhí)行watch對應的回調(diào)函數(shù)
          • 當data對應的key發(fā)生變化時,觸發(fā)user watch實現(xiàn)watch回調(diào)函數(shù)的執(zhí)行

          computed運行原理

          • computed的屬性是動態(tài)掛載到vm實例上的,和普通的響應式數(shù)據(jù)在data里聲明不同
          • 設置computed的getter,如果執(zhí)行了computed對應的函數(shù),由于函數(shù)會讀取data屬性值,因此又會觸發(fā)data屬性值的getter函數(shù),在這個執(zhí)行過程中就可以處理computed相對于data的依賴收集關系了
          • 首次計算computed的值時,會執(zhí)行vm.computed屬性對應的getter函數(shù)(用戶指定的computed函數(shù),如果沒有設置getter,那么將當前指定的函數(shù)賦值computed屬性的getter),進行上述的依賴收集
          • 如果computed的屬性值又依賴了其他computed計算屬性值,那么會將當前target暫存到棧中,先進行其他computed計算屬性值的依賴收集,等其他計算屬性依賴收集完成后,在從棧中pop出來,繼續(xù)進行當前computed的依賴收集
           var vm=new Vue({
           el: '#demo',
           data: {
           firstName: 'Foo',
           lastName: 'Bar'
           },
           computed: {
           fullName: function () {
           returnthis.firstName + ' ' + this.lastName
           }
           }
           })
          

          由于 this.firstName 和 this.lastName (上面是Vue官方示例)都是響應式變量,因此會觸發(fā)它們的 getter,根據(jù)我們之前的分析,它們會把自身持有的 dep 添加到當前正在計算的 watcher 中,這個時候Dep.target就是這個 computed watcher,具體步驟如下:

          • data 屬性初始化 getter setter
          • computed 計算屬性初始化,提供的函數(shù)將用作屬性 vm.fullName 的 getter
          • 當首次獲取 fullName 計算屬性的值時,Dep 開始依賴收集
          • 在執(zhí)行 message getter 方法時,如果 Dep 處于依賴收集狀態(tài),則判定firstName和lastName為fullName 的依賴,并建立依賴關系
          • 當firstName或lastName 發(fā)生變化時,根據(jù)依賴關系,觸發(fā) fullName 的重新計算
          • 如果計算值沒有發(fā)生變化,不會觸發(fā)視圖更新

          通過以上的分析,我們知道計算屬性本質(zhì)上就是一個 computed watcher,也了解了它的創(chuàng)建過程和被訪問觸發(fā) getter 以及依賴更新的過程,其實這是最新的計算屬性的實現(xiàn),之所以這么設計是因為 Vue 想確保不僅僅是計算屬性依賴的值發(fā)生變化,而是當計算屬性最終計算的值發(fā)生變化才會觸發(fā)渲染 watcher 重新渲染,本質(zhì)上是一種優(yōu)化。

          computed計算值為什么還可以依賴另外一個computed計算值

          小提示:這個問題當時完全不知道,哎,官方源碼的套路太深了......

          這里希望有大神可以補充說明一下。

          周期函數(shù)有哪些(beforeCreated和created中間都做了什么

          初始化 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')
          

          小結(jié)

          51信用卡的這次面試其實面試官考察的點還是蠻深入的,問了一些Vue底層源碼的實現(xiàn),總體感覺自己回答的還可以,但是面試官說:你應該去阿里...

          阿里部門未知(一面)

          說說Webpack的實現(xiàn)原理

          小提示:這個直接回答不知道,問題較大,我這里猜測一下是類似Babel和AST抽象語法樹相關,有空去看下源碼。

          這個問題希望同學可以補充一下。

          首屏優(yōu)化有哪些解決方案

          小提示:這個問題在回答懶加載的過程中,面試官追問懶加載的Webpack配置,我說了和代碼切割相關。

          關于懶加載,這里推薦一篇非常好的文章:Webpack 大法之 Code Splitting。

          Node.js的加載機制(require和module.exports)

          小提示:這個問題其實是非常常見的問題,建議大家閱讀一下源碼,有些也可能會問一下比較簡單的問題,例如module.exports和exports的區(qū)別,或者也可能問CommonJS引入和ES6引入的區(qū)別。

          你覺得你最擅長什么

          小提示:這個問題是個大坑阿,我這里直接回答我什么都不擅長,這樣回答顯然面試官是不會不滿意的,建議大家在面試前好好想想自己到底擅長啥。

          React和Vue的區(qū)別

          小提示:這里React真的好久沒用了,幾乎忘記了,大致說了下單向數(shù)據(jù)流、雙向數(shù)據(jù)綁定、數(shù)據(jù)監(jiān)聽方式、JSX以及Vue的單文件組件、函數(shù)式編程、Vue的指令之類的。

          這個問題希望同時熟悉React和Vue的同學可以補充一下。

          React、Vue和JQuery在什么場景下怎么選型

          這個問題希望同學可以補充一下。

          Vue的響應式原理

          什么情況下會阻塞DOM渲染

          小提示:面試官這里應該想問DOM渲染的過程中可能有哪些情況會阻塞渲染。我當時回答不知道。

          這個問題希望同學可以補充一下。

          有哪些異步函數(shù)

          小提示:回答了宏任務和微任務。

          講講MVVM,說說與MVC有什么區(qū)別

          小提示:這個問題我專門發(fā)了一篇掘金文章,但是很多人好像都不是很感興趣的樣子,但是面試官真的就問了這樣一個問題。

          這里推薦我之前寫的掘金文章基于Vue實現(xiàn)一個簡易MVVM/MV*設計模式的演變歷史,一開始重點講解了MVC、MVP以及MVVM的演變過程和區(qū)別。

          阿里CBU技術部(一面)

          說說z-index有什么需要注意的地方

          小提示:真的忘記的差不多了,就簡單說了只能在同一層疊上下文中進行z-index值比較、和絕對定位的關系,z-index值不需要設置過大,只需要理清楚層級關系即可。面試官追問了z-index值和background的覆蓋關系,還追問了絕對定位元素以及后來居上的準則。面試官還問了z-index默認值是什么,0和auto有沒有區(qū)別?真的對于CSS可能平常就用的不多,所以這個問題答的不是很好。

          可能面試官最想知道的是下面這張圖:

          這里附上張鑫旭的文章深入理解CSS中的層疊上下文和層疊順序。

          這里由于回答了定位,面試官追問固定定位的元素是相對于什么進行定位?相對定位會脫離正常文檔流么?絕對定位是相對于什么元素進行定位?

          熟悉CSS3動畫么

          小提示:CSS3動畫硬件加速?CSS3動畫的性能問題(重繪和重流,是否需要脫離正常文檔流)?這個我當時答不知道,確實平常用的很少,如果熟悉Vue過渡動畫的同學可以講講過渡動畫?

          有沒有做過什么可視化的項目

          小提示:我的回答:地圖算么?基于OpenLayers設計過地圖的Vue組件庫。

          對于可視化希望同學可以補充一下。

          你覺得你最擅長的是什么

          小提示:這個問題簡直就是給人挖坑。

          Flex實現(xiàn)兩列布局

          這里簡單實現(xiàn)一下(其實應該使用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;
           }
          

          ES6/ES7/ES8的特性

          說說DOM事件流

          小提示:面試官追問事件委托有什么優(yōu)點(起碼兩個以上)、target/currentTarget/relateTarget具體指向什么目標。

          你覺得你有做過推動流程或者改善流程的事件么,舉例說明

          小提示:這個如果做過什么規(guī)范或者開發(fā)工具之類的,應該比較好回答。

          小結(jié)

          總體來說這次面試面得很細,有些知識點已經(jīng)忘記,建議大家面試前把一些感覺不是很熟悉的原生知識點回憶起來,尤其是在開發(fā)中都不怎么會使用一些CSS樣式設計的童鞋(現(xiàn)在很多都是組件庫的設計方案,樣式早已經(jīng)封裝掉了)。

          阿里企業(yè)智能事業(yè)部(一面)

          Event Loop

          Webpack的loader和plugins的區(qū)別

          小提示:當時直接回答不知道,確實Webpack我只會用,還沒了解過內(nèi)部的實現(xiàn)原理和構成。這個后續(xù)無論如何都要好好理解一下原理。

          這個問題希望同學可以補充一下。

          HTTP狀態(tài)碼206是干什么的

          小提示:工作中沒有遇到過需要上傳下載大型文件,所以這個問題當時老老實實回答不知道。具體應該和斷點續(xù)傳相關,可能也需要回答一些range的頭部信息等。

          React高階組件的作用有哪些

          小提示:好久沒用過React了,大致只知道Racct是單向數(shù)據(jù)流的,利用高階組件可以實現(xiàn)類似于Vue的雙向數(shù)據(jù)綁定。

          這個問題希望同學可以補充一下。

          React和Vue的區(qū)別

          Service Worker有哪些作用

          小提示:當時怕說錯,老老實實回答不知道。后來查了一下應該和緩存以及HTTP請求攔截相關。

          這個問題希望同學可以補充一下。

          跨域

          文件上傳的二進制具體是怎么處理的

          小提示:只知道上傳的頭信息是application/x-www-form-urlencoded,也可以對上傳的文件的數(shù)據(jù)進行攔截處理,例如對上傳文件的信息進行加密處理。

          這個問題希望同學可以補充一下。

          Vue響應式原理

          首屏加載性能優(yōu)化

          小結(jié)

          其實這一次面試自己感覺面試的不是很好(盡管面試官問的確實比我上面列出的問題多),因為有好幾個問題自己確實不清楚。這里再次建議大家不知道就是回答不知道,這樣不會對面試官造成一些負面印象。這一次面試能夠通過運氣占了很大一部分。

          阿里企業(yè)智能事業(yè)部(二面)

          computed的實現(xiàn)原理

          Vue的整個實現(xiàn)原理

          小提示:當時面試官問的蠻好玩的,他問從開始寫一個.vue文件開始到DOM渲染到頁面上,Vue做了哪些工作。然后我當時沒理解面試官是要問vue-loader?DOM樹的渲染過程?來來回回試探性的問了面試官幾次,才理解原來面試官想知道Vue源碼的整個實現(xiàn)過程。

          大家如果想了解Vue源碼實現(xiàn)的整個粗略過程,可以看下之前寫的文章基于Vue實現(xiàn)一個簡易MVVM/Vue的運行機制簡述。

          通訊

          小提示:由于這邊涉及到一些海康的設備(上下位機通信),面試官問我如何知道上位機軟件給下位機設備發(fā)送了5次信息。這個其實大部分Web前端開發(fā)在工作上很難遇到類似的問題,辛虧我以前畢業(yè)設計中做過上下位機的TCP通訊。后來我從Leader面那里了解到二面面試官應該是做iot物聯(lián)網(wǎng)開發(fā)這一塊的。

          請求幀數(shù)據(jù)結(jié)構如下:

          Chrome插件如何屏蔽廣告

          小提示:這個問題當時回答不知道,其實后面想想最簡單的辦法是先找出廣告元素的一些通用特性,然后在Chrome插件中通過注入腳本的形式將這些廣告元素隱藏掉。

          這里不知道有沒有更好的其他方式,例如不知道Service Work對請求攔截處理是否可以有效屏蔽廣告等,這個問題希望同學可以補充一下。

          如何判斷兩個變量相等

          小提示:這里需要分基本類型和引用類型,面試官在這里具體想問的是Object.is的實現(xiàn)原理。這是面試官問我的第一個問題,當時直接回答不知道,內(nèi)心都覺得接下來要涼涼了。

          Watch的運行原理

          Vue的數(shù)據(jù)為什么頻繁變化但只會更新一次

          小提示:這里問的是Vue源碼對于視圖更新的優(yōu)化。我這里的回答是亂糟糟的,希望有同學能夠給出一個精準并且簡短的回答。

          Vue 異步執(zhí)行 DOM 更新。只要觀察到數(shù)據(jù)變化,Vue 將開啟一個隊列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)改變。如果同一個 watcher 被多次觸發(fā),只會被推入到隊列中一次。這種在緩沖時去除重復數(shù)據(jù)對于避免不必要的計算和 DOM 操作上非常重要。然后,在下一個的事件循環(huán)“tick”中,Vue 刷新隊列并執(zhí)行實際 (已去重的) 工作。Vue 在內(nèi)部嘗試對異步隊列使用原生的 Promise.then 和 MessageChannel,如果執(zhí)行環(huán)境不支持,會采用 setTimeout(fn, 0) 代替。

          另外,關于waiting變量,這是很重要的一個標志位,它保證flushSchedulerQueue回調(diào)($nextTick中執(zhí)行)允許被置入callbacks一次。

          因為Vue的事件機制是通過事件隊列來調(diào)度執(zhí)行,會等主進程執(zhí)行空閑后進行調(diào)度,所以先會去等待所有的同步代碼執(zhí)行完成之后再去一次更新。這樣的性能優(yōu)勢很明顯,比如:

          現(xiàn)在有這樣的一種情況,mounted的時候test的值會被循環(huán)執(zhí)行++1000次。每次++時,都會根據(jù)響應式觸發(fā)setter->Dep->Watcher->update->run。如果這時候沒有異步更新視圖,那么每次++都會直接操作DOM更新視圖,這是非常消耗性能的。所以Vue實現(xiàn)了一個queue隊列,在下一個tick(或者是當前tick的微任務階段)統(tǒng)一執(zhí)行queue中Watcher的run。同時,擁有相同id的Watcher不會被重復加入到該queue中去,所以不會執(zhí)行1000次Watcher的run。最終更新視圖只會直接將test對的DOM的0變成1000。保證更新視圖操作DOM的動作是在當前棧執(zhí)行完以后下一個tick(或者是當前tick的微任務階段)的時候調(diào)用,大大優(yōu)化了性能。

          執(zhí)行順序update -> queueWatcher -> 維護觀察者隊列(重復id的Watcher處理) -> waiting標志位處理(保證需要更新DOM或者Watcher視圖更新的方法flushSchedulerQueue只會被推入異步執(zhí)行的$nextTick回調(diào)數(shù)組一次) -> 處理$nextTick(在為微任務或者宏任務中異步更新DOM)->

          • Vue是異步更新Dom的,Dom的更新放在下一個宏任務或者當前宏任務的末尾(微任務)中進行執(zhí)行

          由于VUE的數(shù)據(jù)驅(qū)動視圖更新是異步的,即修改數(shù)據(jù)的當下,視圖不會立刻更新,而是等同一事件循環(huán)中的所有數(shù)據(jù)變化完成之后,再統(tǒng)一進行視圖更新。在同一事件循環(huán)中的數(shù)據(jù)變化后,DOM完成更新,立即執(zhí)行nextTick(callback)內(nèi)的回調(diào)。

          vue和react一樣,對dom的修改都是異步的。它會在隊列里記錄你對dom的操作并進行diff操作,后一個操作會覆蓋前一個,然后更新dom。

          Event Loop

          除了Flex還可以用什么進行布局

          小提示:我猜這里面試官想問的是Grid,當時說不知道。

          絕對定位、固定定位和z-index

          小提示:感謝CBU技術部的面試官。

          絕對定位

          • 一旦給元素加上absolute或float就相當于給元素加上了display:block
          • absolute元素覆蓋正常文檔流內(nèi)元素(不用設z-index,自然覆蓋)
          • 可以減少重繪和回流的開銷(如absolute+ top:-9999em,或absolute + visibility:hidden,將動畫效果放到absolute元素中)

          屬性介紹

          • static,默認值。位置設置為static的元素,它始終會處于文檔流給予的位置。
          • inherit,規(guī)定應該從父元素繼承 position 屬性的值。但是任何的版本的 Internet Explorer (包括 IE8)都不支持屬性值 “inherit”。
          • fixed,生成絕對定位的元素。默認情況下,可定位于相對于瀏覽器窗口的指定坐標。元素的位置通過 “l(fā)eft”, “top”, “right” 以及 “bottom” 屬性進行規(guī)定。不論窗口滾動與否,元素都會留在那個位置。但當祖先元素具有transform屬性且不為none時,就會相對于祖先元素指定坐標,而不是瀏覽器窗口。
          • absolute,生成絕對定位的元素,相對于距該元素最近的已定位的祖先元素進行定位。此元素的位置可通過 “l(fā)eft”、”top”、”right” 以及 “bottom” 屬性來規(guī)定。
          • relative,生成相對定位的元素,相對于該元素在文檔中的初始位置進行定位。通過 “l(fā)eft”、”top”、”right” 以及 “bottom” 屬性來設置此元素相對于自身位置的偏移。

          浮動、絕對定位和固定定位會脫離文檔流,相對定位不會脫離文檔流,絕對定位相對于該元素最近的已定位的祖先元素,如果沒有一個祖先元素設置定位,那么參照物是body層。

          絕對定位相對于包含塊的起始位置:

          • 如果祖先元素是塊級元素,包含塊則設置為該元素的內(nèi)邊距邊界。
          • 如果祖先元素是行內(nèi)元素,包含塊則設置為該祖先元素的內(nèi)容邊界。

          問答題:

          • 定位的元素的起始位置為父包含塊的內(nèi)邊距(不會在border里,除非使用負值,會在padding里)
          • 定位的元素的margin還是能起作用的
          • background屬性是會顯示在border里的
          • z-index是有層疊層級的,需要考慮同一個層疊上下文的層疊優(yōu)先級
          • z-index是負值不會覆蓋包含塊的背景色(但是如果有內(nèi)容,會被包含塊的內(nèi)容覆蓋)
          • z-index的值影響的元素是定位元素以及flex盒子
          • 上面一個定位元素,下面一個正常流的元素,定位元素會覆蓋在正常流元素之上,除非給z-index是負值
          • 頁面根元素html天生具有層疊上下文,稱之為“根層疊上下文”

          小結(jié)

          這一次面試官問我的第一個問題Object.is就沒答上來,不過面試官顯然沒有因為開頭答的不好就否定面試者。大家如果在面試時第一個問題就答不上來,不要慌,要保持良好的心態(tài),把接下來能答的問題好好答上來。可能很多同學會疑問,好像還有好幾個問題感覺沒答上來,但是可能只要有一個問題答的非常出彩,仍然可以彌補那些沒答上來的問題(這里面試官當時說Vue源碼的實現(xiàn)過程我說的比較清楚,還沒有一個面試者答的比我更清楚的)。

          阿里企業(yè)智能事業(yè)部(Leader面)

          三面是Leader現(xiàn)場面,我當時特別擔心有贊二面的情況發(fā)生,冷不丁又給你來一道算法題,這些真是我最不擅長的點。因為有點心虛我就問了下在阿里的師兄(師兄可能也做招聘工作,當時還怪我沒有找他內(nèi)推...),他說現(xiàn)場面其實最主要的是好好準備簡歷上的內(nèi)容,面試官一般都會根據(jù)簡歷進行問答,還說他當時面試阿里時會讓他畫一些框架層次圖(這個我當時沒在意,結(jié)果面試官確實讓我根據(jù)其中某個項目畫一個框架層次圖)。Leader面的時候在場的有兩個面試官和一個HR。

          Leader(一)面試

          先是進來一個氣場很足的Leader,看起來很權威,但是問問題還蠻隨意的,就簡單的讓我介紹一下自己做的項目,然后翻看了我做的一些東西。感覺他好像有點心不在焉,翻看的很隨意,我在回答問題的時候用余光關注了一下大佬的表情,感覺他在我項目經(jīng)歷那一塊停留了非常長的時間。

          Leader(二)面試

          我正回答著自己的項目經(jīng)歷,Leader二和HR進來了,等我回答完Leader一就讓Leader二開始面我。Leader二就問了我其中的兩個項目。問我的第一個項目是自己做的公司內(nèi)部的工具,他問這個平臺有什么可以衡量的數(shù)據(jù)表明公司內(nèi)部人員的使用情況。我回答當時因為領導覺得沒必要做,就沒有做數(shù)據(jù)統(tǒng)計這一塊,告訴了他數(shù)據(jù)庫里的一些真實數(shù)據(jù)情況。然后他問PV、UV應該怎么統(tǒng)計(我當時還厚臉皮的問他PV和UV是什么)?如果訪問的頁面出不來PV怎么統(tǒng)計?頁面有沒有做什么行為監(jiān)測?頁面訪問量過大怎么處理?我大致講了一些我的思路。

          接著問我第二個項目(Low Code相關),我就回答了這個項目的技術體系,從以前做了什么到現(xiàn)在做到什么程度,到未來需要做成什么樣,統(tǒng)統(tǒng)仔細的說了一遍。Leader二就問我未來做成什么樣能不能思考一下怎么做,給了我5分鐘的時間(這期間他一直反復的在翻閱我的簡歷)。然后我就假裝思考了5分鐘左右,其實腦子里一片空白,當時對于未來要做成什么樣還只是個構思。然后Leader二還是很體貼的,他說你可以在墻上畫一畫(墻上可以寫字),我就大致畫了畫,Leader二問我能不能畫一畫這個項目的框架層次圖,我就簡單的畫了畫...最后Leader二直接說你們做的太Low了,這個(Low Code)在我們這里已經(jīng)是兩年前的技術了...(這個我還是要解釋下,我所在的部門從開始用Vue到目前只有短短的兩年時間,在這兩年時間里技術體系還是飛速的在沉淀和發(fā)展,我離開之前已經(jīng)構思并實現(xiàn)了部分Vue技術棧的Low Code解決方案,如果這方面感興趣的同學也可以找我溝通)。

          Leader二還蠻好玩的,他說Low Code如果真的做出來了,都沒前端什么事情了,那你干嘛去?順著這個問題他還問我未來的前端應該怎么發(fā)展?未來前端有哪些可以挖掘的點?我回答了一些Graphql、可視化等,我還說了一個特別搞笑的回答,我說從以往的發(fā)展來看,前端應該搶占后端的資源,把后端限制我們的事情讓前端也能做,讓前端更加解放。Leader二當場就進行了反駁,說是要有價值才做,而不是為了能做而做,嚇得我不輕...然后Leader二還詳細的跟我解釋了未來發(fā)展這個問題他希望得到什么回答,當時還是覺得Leader二蠻親切的。

          HR面試

          Leader二問完以后HR就接著問我了以下幾個問題:

          • 為什么要離開現(xiàn)在的公司
          • 以前公司的崗位制度是什么樣
          • 你是校招進去的么
          • 你現(xiàn)在的崗位等級情況
          • 你的績效情況
          • 你領導對你的評價是怎么樣的
          • 領導是不是經(jīng)常找你溝通

          然后Leader一順著HR問了一個小問題:

          • 你未來對于你的職業(yè)有什么規(guī)劃

          最后問我還有什么想問的,我當時已經(jīng)被三個人問的有點迷迷糊糊了,然后想了想說沒有。

          小結(jié)

          這次現(xiàn)場面其實我感覺自己面得不是很好,總感覺自己要掛了。總共面了將近1個半小時左右,尤其是Leader二的問題很多不是他想要的答案,但是最終居然過了。智能事業(yè)部(HR面)

          企業(yè)智能事業(yè)部Leader面后又收到了HR面的面試通知,這一輪面試大致問了以下問題:

          • 你為什么要離開現(xiàn)在的公司
          • 你們公司的崗位等級是怎么評定的,你現(xiàn)在是什么崗位等級
          • 談談你在公司的績效情況
          • 你覺得你做的最有成就感的一件事
          • 你一般解決問題的方法有哪些
          • 你是因為什么契機選擇做前端
          • 你有對你所在的公司做過什么流程或制度規(guī)范上的改進么
          • 你最近在看什么書,和工作相關么,你為什么要看這些書
          • 看到你之前還面試了其他兩個部門都掛在了一面,你感覺是什么原因
          • 你期望的薪資待遇是多少

          小提示:這里HR會問的其實不止這些問題,例如你為什么喜歡Web前端這個崗位、你未來的職業(yè)規(guī)劃、你覺得你的優(yōu)點和缺點有哪些、為什么選擇阿里巴巴、對之前幾個面試官做下評價、你用過阿里的哪些產(chǎn)品順便談談這些產(chǎn)品的優(yōu)缺點、你對于互聯(lián)網(wǎng)是怎么理解的...

          小結(jié)

          對于HR面還是要好好準備的,尤其是有些問題還是很容易挖坑的,例如你為什么離開現(xiàn)在的公司(你當然不應該抱怨現(xiàn)在的公司有哪些不好的地方,更多的應該表明自己想要尋找更好的發(fā)展機會,自己的一些現(xiàn)實因素,比如對于我而言是現(xiàn)在應聘的公司離自己的家更近,又或者是自己工作到達了迷茫期,想跳出迷茫期等等),你覺得你做的最有成就感的一件事(你要是說個簡單的,HR會覺得你工作能力不強),你一般解決問題的方法有哪些(HR當然也想考察你解決問題的能力,你要是說什么百度啊之類的HR當然會覺得你解決問題的能力不強),你期望的薪資待遇是多少(你要是不喜歡這家公司,可以期望高一些,你要是很喜歡這家公司面試過程很愉快上浮個30%左右,面試過程一般上浮個20%左右)。

          性是HTML元素提供的附國信息

          HTML元素可以設置屬性

          屬性可以在元素中添加附加信息

          屬性一般描述于開始標簽

          屬性總是以名稱/值對應的形式出現(xiàn),例如:name="value"

          例,鏈接地址是href的屬性

          <a >鏈接地址是href的屬性</a>

          HTML屬性常用引用屬性值

          屬性值應該始終被包含在引號內(nèi)

          雙引號是常用的,單引號也沒有問題,

          如果屬性值本身就包含了雙引號,即么則必須引用單引號,例:name='John"ShotGun"Nelson'

          HTML提示:使用小寫屬性

          屬性和屬性值對大小寫不敏感。

          HTML屬性參考

          calss 為HMTL元素定義一個或多個名

          id 定義元素的唯一id

          style 規(guī)定元素的行內(nèi)樣式

          title 描述元素的額外信息

          HTML標題

          HTML注釋

          類似于對代碼進行備注,默認有兩種試

          1、<!-- 這是一個小的注釋 -->

          常用于一小段注釋

          2、//注釋 有時候不起作用,不知道為啥,知道的回復下啦

          HTML提示,如何查看源代碼

          如果你想看,在網(wǎng)頁中,單擊右鍵,然后選擇查看“源文件”或者醒看頁面源代碼即可;

          TML 基礎

          非常簡單的HTML文檔

          HTML 標題

          HTML 段落

          HTML 鏈接

          HTML 圖片

          實例解析

          HTML 標題

          HTML 標題

          在html源碼中插入注釋

          插入水平線

          實例解析

          HTML 段落

          HTML 段落

          更多段落

          本例演示在 HTML 文檔中折行的使用。

          HTML 格式化的某些問題。

          實例解析

          HTML 文本格式化

          文本格式化

          此例演示如何使用 pre 標簽對空行和空格進行控制。

          此例演示不同的"計算機輸出"標簽的顯示效果。

          此例演示如何在 HTML 文件中寫地址。

          此例演示如何實現(xiàn)縮寫或首字母縮寫。

          此例演示如何改變文字的方向。

          此例演示如何實現(xiàn)長短不一的引用語。

          文本下劃線與刪除線

          實例解析

          HTML 樣式

          HTML Style 元素

          背景色樣式

          字體樣式,顏色,大小

          文本對齊樣式

          設置文本字體

          設置文本字體大小

          設置文本字體顏色

          設置文本字體,字體大小,字體顏色

          HTML使用不同樣式

          沒有下劃線的鏈接

          鏈接到一個外部樣式表

          實例解析

          HTML 鏈接

          創(chuàng)建超級鏈接

          將圖像作為鏈接

          在新的瀏覽器窗口打開鏈接

          鏈接到同一個頁面的不同位置

          跳出框架

          創(chuàng)建電子郵件鏈接

          創(chuàng)建電子郵件鏈接 2

          實例解析

          HTML 圖像

          插入圖像

          從不同的位置插入圖片

          排列圖片

          本例演示如何使圖片浮動至段落的左邊或右邊。

          制作圖像鏈接

          創(chuàng)建圖像映射

          實例解析

          HTML 表格

          簡單的表格

          沒有邊框的表格

          表格中的表頭

          帶有標題的表格

          跨行或跨列的表格單元格

          表格內(nèi)的標簽

          單元格邊距(Cell padding)

          單元格間距(Cell spacing)

          實例解析

          HTML 列表

          無序列表

          有序列表

          不同類型的有序列表

          不同類型的無序列表

          嵌套列表

          嵌套列表 2

          定義列表

          實例解析

          HTML Forms 和 Input

          創(chuàng)建文本域(Text fields)

          創(chuàng)建密碼域

          復選框

          單選按鈕

          簡單的下拉列表

          預選下拉列表

          本例演示如何創(chuàng)建一個文本域(多行文本輸入控件)。

          創(chuàng)建一個按鈕

          本例演示如何在數(shù)據(jù)周圍繪制一個帶標題的框。

          帶有文本域與輸入域的表單

          帶有復選框與提交按鈕的form表單

          帶有單選框與提交按鈕的表單

          發(fā)送郵件表單

          實例解析

          HTML iframe

          內(nèi)聯(lián)框架 (HTML頁面中插入框架)

          實例解析

          HTML 頭部元素

          描述了文檔標題

          HTML頁面中默認的URL鏈接

          提供文檔元數(shù)據(jù)

          實例解析

          HTML 腳本

          插入一個腳本

          使用 <noscript> 標簽

          實例解析

          如您還有不明白的可以在下面與我留言或是與我探討QQ群308855039,我們一起飛!


          主站蜘蛛池模板: 中文字幕一区日韩在线视频| 国产综合无码一区二区辣椒| 久久久国产精品无码一区二区三区| 国产精品女同一区二区久久| 久久国产午夜一区二区福利 | 日本精品一区二区三区视频| 中文国产成人精品久久一区| 成人毛片无码一区二区| 久久精品一区二区免费看| 日韩动漫av在线播放一区| 亚洲av无一区二区三区| 亚洲国产欧美日韩精品一区二区三区| 国产AV午夜精品一区二区三| 波多野结衣高清一区二区三区| 国产在线第一区二区三区| 国产伦理一区二区三区| 国产一区二区三区国产精品| 日本一区二三区好的精华液| 亚洲日韩一区二区一无码| 日本无卡码一区二区三区| 国产一区二区好的精华液| 国产成人高清亚洲一区91| 国产亚洲综合精品一区二区三区| 性色av闺蜜一区二区三区| 波多野结衣一区二区三区高清av | 成人精品一区久久久久| 一区二区日韩国产精品| 精品一区二区三区免费观看| 国产在线精品一区二区不卡麻豆| 91麻豆精品国产自产在线观看一区| 久久久久女教师免费一区| 中文字幕人妻丝袜乱一区三区| 日韩视频一区二区三区| 精品无码一区二区三区爱欲九九 | 精品无码综合一区二区三区| 国产主播一区二区三区在线观看| 精品亚洲一区二区三区在线观看| 亚洲AV福利天堂一区二区三| 亚洲av成人一区二区三区观看在线 | 精品亚洲一区二区三区在线观看 | 香蕉久久ac一区二区三区|