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

視學演算法發表於2020-04-06

前言

本文主要給大家帶來一些我面試的經歷和經驗,希望對正在求職的同學有所幫助。我先大致說下面試之前的個人情況:2017年7月正式入職海康威視數字技術股份有限公司,使用Vue.js技術棧。

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

關於阿里

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

  • 目前Web前端急缺P6和P7(阿里的很多BU都只招P7了)

  • 新的BU你進來即是元老????????????

  • 前端技術體系大部分需要一起重新開拓,可以學習到更多的新內容

  • 主要負責PC端、客戶端、釘釘E應用以及支付寶小程式的開發(我本人完全不會小程式,不用擔心????????????)

  • 技術棧是React(如果你是Vue技術棧完全不用擔心,因為我也是????????????)

  • 其他BU面試可能有五輪,我們這邊只有4輪面試

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

簡歷

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

  • 基本資料

  • 專業技能

  • 工作經歷

  • 實習經歷(可選)

  • 專案經歷

小提示:在基本資料裡一定要填寫正確的郵箱地址,我在前期面試的時候都沒有開啟郵箱檢視面試情況,導致一些面試的時間點和麵試結果都不清楚(一直以為會發簡訊通知)。

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

對於簡歷這裡提一點,在寫自己的專業技能專案經歷時儘量不要給自己挖坑,這裡展示一下我的專業技能(我會的不多):

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

  • 熟悉Vue.js框架

切忌寫一大堆讓人感覺花裡胡哨的技能,尤其是一些很淺顯的技能(基本技能除外)。如果你有一些別人很難替代的技能,那這些技能就是亮點了,我這裡就沒什麼亮點技能。有些技能你會但是不熟練,你可以適當的在你的專案經歷中體現出來。對於專案經歷儘量挑自己覺得非常有技術含量的專案進行說明(寧缺毋濫),對於自己參加過但不是特別熟悉的專案儘量不要填寫,防止給自己挖坑。

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

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

面試

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

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

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

  • 心態放平穩,假設第一題你答不上來很正常,面試官不會因為第一題你不會就PASS你

  • 不會的題目一定不要瞎猜,往往面試官給你挖的坑就是希望你往錯的方向猜,一定要答不知道

  • 不要說太多跟當前面試題無關的內容,問你什麼問題儘量就答什麼問題,除非面試官指定你發散一下思維

  • 如果沒有聽懂面試題可以試著詢問面試官,您要問的是關於xxx的問題麼

  • 對於某些問題一定要自己先提前精煉一下(例如作用域鏈、繼承以及原型鏈等問題)

  • 如果面試官問的某項技術自己在某些場景使用過或看到別的場景有使用,可結合這些場景進行講解(讓面試官知道你不僅僅理解它,你還會很好的使用它)

  • 如果是Vue技術棧希望可以深入原始碼或者至少理解一些別人的原始碼分析

  • 如果面試阿里那麼面試之前一定要好好準備這樣一個問題:你覺得你最擅長什麼

  • 面試一定要真誠,切勿投機取巧

  • 面試態度一定要謙虛

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

  • 大部分答案都是借鑑別人的部落格

  • 有些答案不一定合理

  • 有些答案寫的很零散

  • 有些答案會舉一反三

  • 有些題目太基礎或者重複了就沒有寫答案

  • 有些題目太巨集觀或者不知道怎麼回答合理,希望大家可以在評論中補充答案供更多的人受益

有贊(一面)

說說CSS選擇器以及這些選擇器的優先順序

  • !important

  • 內聯樣式(1000)

  • ID選擇器(0100)

  • 類選擇器/屬性選擇器/偽類選擇器(0010)

  • 元素選擇器/關係選擇器/偽元素選擇器(0001)

  • 萬用字元選擇器(0000)

你知道什麼是BFC麼

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

什麼是BFC

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

觸發BFC的條件

  • 根元素或其它包含它的元素

  • 浮動元素 (元素的 float 不是 none)

  • 絕對定位元素 (元素具有 position 為 absolute 或 fixed)

  • 內聯塊 (元素具有 display: inline-block)

  • 表格單元格 (元素具有 display: table-cell,HTML表格單元格預設屬性)

  • 表格標題 (元素具有 display: table-caption, HTML表格標題預設屬性)

  • 具有overflow 且值不是 visible 的塊元素

  • 彈性盒(flexinline-flex

  • display: flow-root

  • column-span: all

BFC的約束規則

  • 內部的盒會在垂直方向一個接一個排列(可以看作BFC中有一個的常規流)

  • 處於同一個BFC中的元素相互影響,可能會發生外邊距重疊

  • 每個元素的margin box的左邊,與容器塊border box的左邊相接觸(對於從左往右的格式化,否則相反),即使存在浮動也是如此

  • BFC就是頁面上的一個隔離的獨立容器,容器裡面的子元素不會影響到外面的元素,反之亦然

  • 計算BFC的高度時,考慮BFC所包含的所有元素,連浮動元素也參與計算

  • 浮動盒區域不疊加到BFC上

BFC可以解決的問題

  • 垂直外邊距重疊問題

  • 去除浮動

  • 自適用兩列布局(float + overflow

瞭解盒模型麼

包括內容區域內邊距區域邊框區域外邊距區域阿里p6前端面經(全文3w字)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>

利用float + margin實現

    .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實現

    .box {
height: 200px;
}

.box > div {
height: 100%;
}

.box-left {
width: 200px;
float: left;
background-color: blue;
}

.box-right {
overflow: hidden;
background-color: red;
}

利用flex實現

這裡不是最佳答案,應該是使用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反向代理。

跨域行為

  • 同源策略限制、安全性考慮

  • 協議、IP和埠不一致都是跨域行為

JSONP

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

Web前端事先定義一個用於獲取跨域響應資料的回撥函式,並通過沒有同源策略限制的script標籤發起一個請求(將回撥函式的名稱放到這個請求的query引數裡),然後服務端返回這個回撥函式的執行,並將需要響應的資料放到回撥函式的引數裡,前端的script標籤請求到這個執行的回撥函式後會立馬執行,於是就拿到了執行的響應資料。

缺點:JSONP只能發起GET請求

如何實現一個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的呼叫來源(Referer),服務端判斷Referer是否是白名單,或者部署隨機Token來防禦。

XSS漏洞

不嚴謹的 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 後的引數並且限制長度(進行字元轉義,例如<換成&lt,>換成&gt)等,這樣返回的指令碼內容會變成文字格式,指令碼將不會執行。

伺服器被黑,返回一串惡意執行的程式碼

可以將執行的程式碼轉發到服務端進行校驗JSONP內容校驗,再返回校驗結果。

CORS(跨域資款共享)

小提示:如果你回答跨域解決方案CORS,那麼面試官一定會問你實現CORS的響應頭資訊Access-Control-Allow-Origin。

什麼是CORS

CORS(跨域資源共享 Cross-origin resource sharing)允許瀏覽器向跨域伺服器發出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:該欄位可選。它的值是一個布林值,表示是否允許傳送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請求會額外傳送的頭資訊欄位,上例是X-Custom-Header。

如果瀏覽器否定了"預檢"請求,會返回一個正常的HTTP回應,但是沒有任何CORS相關的頭資訊欄位。這時,瀏覽器就會認定,伺服器不同意預檢請求,因此觸發一個錯誤,被XMLHttpRequest物件的onerror回撥函式捕獲。

JSONP和CORS的對比

  • JSONP只支援GET請求,CORS支援所有型別的HTTP請求

  • JSONP的優勢在於支援老式瀏覽器,以及可以向不支援CORS的網站請求資料

其他跨域解決方案

  • Nginx反向代理

  • postMessage

  • document.domain

HTTP2和HTTP1有什麼區別

相對於HTTP1.0,HTTP1.1的優化:

  • 快取處理:多了Entity tag,If-Unmodified-Since, If-Match, If-None-Match等快取資訊(HTTTP1.0 If-Modified-Since,Expires)

  • 頻寬優化及網路連線的使用

  • 錯誤通知的管理

  • Host頭處理

  • 長連線:HTTP1.1中預設開啟Connection:keep-alive,一定程度上彌補了HTTP1.0每次請求都要建立連線的缺點。

相對於HTTP1.1,HTTP2的優化:

  • HTTP2支援二進位制傳送(實現方便且健壯),HTTP1.x是字串傳送

  • HTTP2支援多路複用

  • HTTP2採用HPACK壓縮演算法壓縮頭部,減小了傳輸的體積

  • 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):有很多屬性,不同的屬性代表的意義也不同:

  • private:客戶端可以快取

  • public:客戶端和代理伺服器都可以快取

  • max-age=t:快取內容將在t秒後失效

  • no-cache:需要使用協商快取來驗證快取資料

  • no-store:所有內容都不會快取

請注意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和響應報文頭,瀏覽器只需要從快取中獲取資訊即可。

  • 如果真的被修改:那麼開始傳輸響應一個整體,伺服器返回:200 OK

  • 如果沒有被修改:那麼只需傳輸響應header,伺服器返回:304 Not Modified

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

  • 如果沒有被修改:則開始`繼續'傳送檔案,伺服器返回: 200 OK

  • 如果檔案被修改:則不傳輸,伺服器返回: 412 Precondition failed (預處理錯誤)

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

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

If-Match:條件請求,攜帶上一次請求中資源的ETag,伺服器根據這個欄位判斷檔案是否有新的修改

If-None-Match:再次請求伺服器時,瀏覽器的請求報文頭部會包含此欄位,後面的值為在快取中獲取的標識。伺服器接收到次報文後發現If-None-Match則與被請求資源的唯一標識進行對比。

  • 不同,說明資源被改動過,則響應整個資源內容,返回狀態碼200。

  • 相同,說明資源無心修改,則響應header,瀏覽器直接從快取中獲取資料資訊。返回狀態碼304.

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

  • 瀏覽器位址列中寫入URL,回車瀏覽器發現快取中有這個檔案了,不用繼續請求了,直接去快取拿(最快)

  • F5就是告訴瀏覽器,別偷懶,好歹去伺服器看看這個檔案是否有過期了。於是瀏覽器就膽膽襟襟的傳送一個請求帶上If-Modify-since

  • Ctrl+F5告訴瀏覽器,你先把你快取中的這個檔案給我刪了,然後再去伺服器請求個完整的資原始檔下來。於是客戶端就完成了強行更新的操作

快取場景

對於大部分的場景都可以使用強快取配合協商快取解決,但是在一些特殊的地方可能需要選擇特殊的快取策略

  • 對於某些不需要快取的資源,可以使用 Cache-control: no-store ,表示該資源不需要快取

  • 對於頻繁變動的資源,可以使用 Cache-Control: no-cache 並配合 ETag 使用,表示該資源已被快取,但是每次都會傳送請求詢問資源是否更新

  • 對於程式碼檔案來說,通常使用 Cache-Control: max-age=31536000 並配合策略快取使用,然後對檔案進行指紋處理,一旦檔名變動就會立刻下載新的檔案

能說說首屏載入優化有哪些方案麼

小提示:如果做過類似優化的同學,可能就比較好回答,沒有做過類似優化的同學可以重點講解一下懶載入(當然我這裡被面試官追問過懶載入的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將會把資源得下載順序權重提高,使得關鍵資料提前下載好,優化頁面開啟速度)

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

  • 全域性變數

  • 環境變數

  • 自己HACK一個@符號,指向特定的路徑

  • HACK require方法

參考

這種問題還是附上參考連結

  • https://segmentfault.com/a/1190000010998044

  • http://chashaobao.net/2017/09/03/alias-require-hack/

  • https://www.zhihu.com/question/26621212

談談你對作用域鏈的理解

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

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

  • 函式的生命週期

  • 變數和函式的宣告

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

函式的生命週期:

建立:JS解析引擎進行預解析,會將函式宣告提前,同時將該函式放到全域性作用域中或當前函式的上一級函式的區域性作用域中。

執行:JS引擎會將當前函式的區域性變數和內部函式進行宣告提前,然後再執行業務程式碼,當函式執行完退出時,釋放該函式的執行上下文,並登出該函式的區域性變數。

變數和函式的宣告:如果變數名和函式名宣告時相同,函式優先宣告。

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

  • AO:Activetion Object(活動物件)

  • VO:Variable Object(變數物件)

VO對應的是函式建立階段,JS解析引擎進行預解析時,所有的變數和函式的宣告,統稱為Variable Object。該變數與執行上下文相關,知道自己的資料儲存在哪裡,並且知道如何訪問。VO是一個與執行上下文相關的特殊物件,它儲存著在上下文中宣告的以下內容:

  • 變數 (var, 變數宣告);

  • 函式宣告 (FunctionDeclaration, 縮寫為FD);

  • 函式的形參

AO對應的是函式執行階段,當函式被呼叫執行時,會建立一個執行上下文,該執行上下文包含了函式所需的所有變數,該變數共同組成了一個新的物件就是Activetion Object。該物件包含了:

  • 函式的所有區域性變數

  • 函式的所有命名引數

  • 函式的引數集合

  • 函式的this指向

作用域鏈:

當程式碼在一個環境中建立時,會建立變數物件的一個作用域鏈(scope chain)來保證對執行環境有權訪問的變數和函式。作用域第一個物件始終是當前執行程式碼所在環境的變數物件(VO)。如果是函式執行階段,那麼將其activation object(AO)作為作用域鏈第一個物件,第二個物件是上級函式的執行上下文AO,下一個物件依次類推。

在《JavaScript深入之變數物件》中講到,當查詢變數的時候,會先從當前上下文的變數物件中查詢,如果沒有找到,就會從父級(詞法層面上的父級)執行上下文的變數物件中查詢,一直找到全域性上下文的變數物件,也就是全域性物件。這樣由多個執行上下文的變數物件構成的連結串列就叫做作用域鏈。

你知道nullundefined有什麼區別麼

閉包有什麼作用

Vue響應式原理

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

如果對於響應式原理不是很清楚可以檢視我之前寫的文章基於Vue實現一個簡易MVVM/資料劫持的實現。

瞭解Event Loop麼

小提示:這個題目問到的概率還是蠻大的,這裡面試官詢問了我瀏覽器端和Node端的Event Loop有什麼不同點。如果想要知道更多瀏覽器端的Event Loop機制可以檢視我之前寫的文章你真的理解$nextTick麼/JS引擎執行緒和事件觸發執行緒/事件迴圈機制。

事件觸發執行緒管理的任務佇列是如何產生的呢?事實上這些任務就是從JS引擎執行緒本身產生的,主執行緒在執行時會產生執行棧,棧中的程式碼呼叫某些非同步API時會在任務佇列中新增事件,棧中的程式碼執行完畢後,就會讀取任務佇列中的事件,去執行事件對應的回撥函式,如此迴圈往復,形成事件迴圈機制。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有什麼區別

       ┌───────────────────────┐
┌─>│ 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 型別;

  • socket 的 close 事件屬於 close callbacks 型別;

  • 其他 MacroTask 都屬於 poll 型別。

  • process.nextTick 本質上屬於 MicroTask,但是它先於所有其他 MicroTask 執行;

  • 所有 MicroTask 的執行時機在不同型別的 MacroTask 切換後。

  • idle/prepare 僅供內部呼叫,我們可以忽略。

  • pending callbacks 不太常見,我們也可以忽略。

如何避免迴流和重繪

瀏覽器渲染過程

阿里p6前端面經(全文3w字)
  • 瀏覽器使用流式佈局模型 (Flow Based Layout)

  • 瀏覽器會把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合併就產生了Render Tree

  • 有了RenderTree就能知道所有節點的樣式,計算節點在頁面上的大小和位置,把節點繪製到頁面上

  • 由於瀏覽器使用流式佈局,對Render Tree的計算通常只需要遍歷一次就可以完成,但table及其內部元素除外,通常需要多次計算且要花費3倍於同等元素的時間,這也是為什麼要避免使用table佈局的原因之一

瀏覽器渲染過程如下:

  • 解析HTML,生成DOM樹

  • 解析CSS,生成CSSOM樹

  • 將DOM樹和CSSOM樹結合,生成渲染樹(Render Tree)

  • Layout(迴流):根據生成的渲染樹,進行迴流(Layout),得到節點的幾何資訊(位置,大小)

  • Painting(重繪):根據渲染樹以及迴流得到的幾何資訊,得到節點的絕對畫素

  • Display:將畫素髮送給GPU,展示在頁面上。(這一步其實還有很多內容,比如會在GPU將多個合成層合併為同一個層,並展示在頁面中。而css3硬體加速的原理則是新建合成層,這裡我們不展開,之後有機會會寫一篇部落格)

何時觸發迴流和重繪

何時發生迴流:

  • 新增或刪除可見的DOM元素

  • 元素的位置發生變化

  • 元素的尺寸發生變化(包括外邊距、內邊框、邊框大小、高度和寬度等)

  • 內容發生變化,比如文字變化或圖片被另一個不同尺寸的圖片所替代。

  • 頁面一開始渲染的時候(這肯定避免不了)

  • 瀏覽器的視窗尺寸變化(因為迴流是根據視口的大小來計算元素的位置和大小的)

何時發生重繪(迴流一定會觸發重繪):

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

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

  • clientWidthclientHeightclientTopclientLeft

  • offsetWidthoffsetHeightoffsetTopoffsetLeft

  • scrollWidthscrollHeightscrollTopscrollLeft

  • widthheight

  • getComputedStyle()

  • getBoundingClientRect()

以上屬性和方法都需要返回最新的佈局資訊,因此瀏覽器不得不清空佇列,觸發迴流重繪來返回正確的值。因此,我們在修改樣式的時候,**最好避免使用上面列出的屬性,他們都會重新整理渲染佇列。**如果要使用它們,最好將值快取起來。

如何避免觸發迴流和重繪

CSS:

  • 避免使用table佈局。

  • 儘可能在DOM樹的最末端改變class。

  • 避免設定多層內聯樣式。

  • 將動畫效果應用到position屬性為absolutefixed的元素上

  • 避免使用CSS表示式(例如:calc()

  • CSS3硬體加速(GPU加速)

JavaScript:

  • 避免頻繁操作樣式,最好一次性重寫style屬性,或者將樣式列表定義為class並一次性更改class屬性

  • 避免頻繁操作DOM,建立一個documentFragment,在它上面應用所有DOM操作,最後再把它新增到文件中

  • 也可以先為元素設定display: none,操作結束後再把它顯示出來。因為在display屬性為none的元素上進行的DOM操作不會引發迴流和重繪

  • 避免頻繁讀取會引發迴流/重繪的屬性,如果確實需要多次使用,就用一個變數快取起來

  • 對具有複雜動畫的元素使用絕對定位,使它脫離文件流,否則會引起父元素及後續元素頻繁迴流

有贊(二面)

小提示:進入現場面試需要注意好好準備自己的簡歷,面試官一般會根據專案進行問答。

筆試題環節

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

  • 作用域

  • 原型鏈(例如例項屬性和原型屬性一樣,刪除例項屬性後可以繼續訪問原型屬性問題)

  • 巨集任務和微任務的列印順序

  • Array.prototype.map的第二個引數

專案問答環節

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

  • 你們產品的伺服器部署在哪裡

  • 你是如何實現一個Tooltip元件的,能寫一下怎麼使用這個元件麼(這算什麼問題...)

  • 我認識你們海康的一些開發,我知道你們的產品按套數賣的...

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

演算法題環節

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

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

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

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

小結

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

滴滴(一面)

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

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

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

基於 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>

此時,使用者點選生成的連結,就會執行對應的指令碼。

XSS攻擊防範

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 = {
'&lt;': '<',
'&gt;': '>',
'&quot;': '"',
'&amp;': '&',
'&#10;': '\n'
}

輸出檢查:使用者的輸入會存在問題,服務端的輸出也會存在問題。一般來說,除富文字的輸出外,在變數輸出到 HTML 頁面時,可以使用編碼或轉義的方式來防禦 XSS 攻擊。例如利用 sanitize-html 對輸出內容進行有規則的過濾之後再輸出到頁面中。

CSRF/XSRF(跨站請求偽造)

CSRF,即 Cross Site Request Forgery,中譯是跨站請求偽造,是一種劫持受信任使用者向伺服器傳送非預期請求的攻擊方式。通常情況下,CSRF 攻擊是攻擊者藉助受害者的 Cookie 騙取伺服器的信任,可以在受害者毫不知情的情況下以受害者名義偽造請求傳送給受攻擊伺服器,從而在並未授權的情況下執行在許可權保護之下的操作。

Cookie

Cookie 是伺服器傳送到使用者瀏覽器並儲存在本地的一小塊資料,它會在瀏覽器下次向同一伺服器再發起請求時被攜帶併傳送到伺服器上。Cookie 主要用於以下三個方面:

  • 會話狀態管理(如使用者登入狀態、購物車、遊戲分數或其它需要記錄的資訊)

  • 個性化設定(如使用者自定義設定、主題等)

  • 瀏覽器行為跟蹤(如跟蹤分析使用者行為等)

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

  • Session Cookie(會話期 Cookie):會話期 Cookie 是最簡單的Cookie,它不需要指定過期時間(Expires)或者有效期(Max-Age),它僅在會話期內有效,瀏覽器關閉之後它會被自動刪除。

  • 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;']);

上述程式碼建立了兩個 Cookie:mycookie 和 test,前者屬於會話期 Cookie,後者則屬於永續性 Cookie。

CSRF攻擊

使登入使用者訪問攻擊者的網站,發起一個請求,由於 Cookie 中包含了使用者的認證資訊,當使用者訪問攻擊者準備的攻擊環境時,攻擊者就可以對伺服器發起 CSRF 攻擊。

在這個攻擊過程中,攻擊者藉助受害者的 Cookie 騙取伺服器的信任,但並不能拿到 Cookie,也看不到 Cookie 的內容。而對於伺服器返回的結果,由於瀏覽器同源策略的限制,攻擊者也無法進行解析。(攻擊者的網站雖然是跨域的,但是他構造的連結是源網站的,跟源網站是同源的,所以能夠攜帶cookie發起訪問)。

但是攻擊者無法從返回的結果中得到任何東西,他所能做的就是給伺服器傳送請求,以執行請求中所描述的命令,在伺服器端直接改變資料的值,而非竊取伺服器中的資料。例如刪除資料、修改資料,新增資料等,無法獲取資料。

CSRF攻擊防範

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

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

新增token驗證:要抵禦 CSRF,關鍵在於在請求中放入攻擊者所不能偽造的資訊,並且該資訊不存在於 Cookie 之中。可以在 HTTP 請求中以引數的形式加入一個隨機產生的 token,並在伺服器端建立一個攔截器來驗證這個 token,如果請求中沒有 token 或者 token 內容不正確,則認為可能是 CSRF 攻擊而拒絕該請求。

介紹一下Graphql

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

什麼是Graphql

GraphQL是一種API查詢語言。API介面的返回值可以從靜態變為動態,即呼叫者來宣告介面返回什麼資料,可以進一步解耦前後端。在Graphal中,預先定義Schema和宣告Type來達到動態獲取介面資料的目的:

  • 對於資料模型的抽象是通過Type來描述的

  • 對於介面獲取資料的邏輯是通過Schema來描述的

為什麼要使用Graphql:

  • 介面數量眾多維護成本高

  • 介面擴充套件成本高

  • 介面響應的資料格式無法預知

  • 減少無用資料的請求, 按需獲取

  • 強型別約束(API的資料格式讓前端來定義,而不是後端定義)

Type(資料模型的抽象)

Type簡單可以分為兩種,一種叫做Scalar Type(標量型別),另一種叫做Object Type(物件型別):

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

Object Type(物件型別):感覺類似於TypeScript的介面型別

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

Schema(模式)

定義了欄位的型別、資料的結構,描述了介面資料請求的規則

Query(查詢、操作型別)

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

  • query(查詢):當獲取資料時,應當選取Query型別

  • mutation(更改):當嘗試修改資料時,應當使用mutation型別

  • subscription(訂閱):當希望資料更改時,可以進行訊息推送,使用subscription型別

Resolver(解析函式)

提供相關Query所返回資料的邏輯。Query和與之對應的Resolver是同名的,這樣在GraphQL才能把它們對應起來。解析的過程可能是遞迴的,只要遇到非標量型別,會嘗試繼續解析,如果遇到標量型別,那麼解析完成,這個過程叫做解析鏈。

說說Vue中$nextTick的實現原理

小提示:如果面試者使用的是Vue技術棧,那麼$nextTick的原理是一個高頻問題,面試者藉此可以追問的東西較多,例如瀏覽器的Event Loop、微任務和巨集任務、Node.js的Event Loop、非同步更新DOM(響應式的資料for迴圈改變了1000次為什麼檢視只更新了一次)、$nextTick歷史版本問題等等。

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

Vue響應式原理

談談對閉包的理解

JSONP的實現原理

CSS中的BFC

如何實現居中

水平居中

  • 若是行內元素,給其父元素設定text-align:center即可實現行內元素水平居中

  • 若是塊級元素,該元素設定margin:0 auto即可(元素需要定寬)

  • 若是塊級元素,設定父元素為flex佈局,子元素設定margin:0 auto即可(子元素不需要定寬)

  • 使用flex 2012年版本佈局,可以輕鬆的實現水平居中,子元素設定如下:

    // 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;
} */



  • 使用絕對定位和CSS3新增的屬性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等於父元素高度

  • 若是塊級元素,設定父元素為flex佈局,子元素設定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;
}
  • 可用 Flex 2012版, 這是CSS佈局未來的趨勢。Flexbox是CSS3新增屬性,設計初衷是為了解決像垂直居中這樣的常見佈局問題:

    .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 效果,某些情形下會出現文字或元素邊界渲染模糊的現象。

居中元素高度固定
  • 設定父元素相對定位,子元素如下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;
}
  • 絕對定位實現(定位元素定寬定高)

    .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 佈局教程:語法篇。面試官追問,那麼除了Flex,你還知道Grid麼?這個由於相容性問題,我一直沒有好好研究過,這裡可檢視阮一峰的文章CSS Grid網格佈局教程。

bind的原始碼實現

小提示:這裡我回答使用函式柯里化加上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。同時對於自己不會的題目強行做了一些解釋說明,其實應該簡潔明瞭的告訴面試官不會。

51信用卡(一面)

說說DOM事件流

在ES5中如何實現繼承

小提示:這裡我說了很多,從借用建構函式到組合繼承到寄生組合繼承,但面試官其實最想聽到的是寄生組合繼承。面試官還追問我具體要如何實現寄生組合繼承。當然這裡其實問的問題還可以很多,比如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)
}
}
}

Vue中的computed實現原理

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

watch的實現原理

watch的分類:

  • deep watch(深層次監聽)

  • user watch(使用者監聽)

  • computed watcher(計算屬性)

  • sync watcher(同步監聽)

watch實現過程:

  • watch的初始化在data初始化之後(此時的data已經通過Object.defineProperty的設定成響應式)

  • watch的key會在Watcher裡進行值的讀取,也就是立馬執行get獲取value(從而實現data對應的key執行getter實現對於watch的依賴收集),此時如果有immediate屬性那麼立馬執行watch對應的回撥函式

  • 當data對應的key發生變化時,觸發user watch實現watch回撥函式的執行

computed執行原理

  • computed的屬性是動態掛載到vm例項上的,和普通的響應式資料在data裡宣告不同

  • 設定computed的getter,如果執行了computed對應的函式,由於函式會讀取data屬性值,因此又會觸發data屬性值的getter函式,在這個執行過程中就可以處理computed相對於data的依賴收集關係了

  • 首次計算computed的值時,會執行vm.computed屬性對應的getter函式(使用者指定的computed函式,如果沒有設定getter,那麼將當前指定的函式賦值computed屬性的getter),進行上述的依賴收集

  • 如果computed的屬性值又依賴了其他computed計算屬性值,那麼會將當前target暫存到棧中,先進行其他computed計算屬性值的依賴收集,等其他計算屬性依賴收集完成後,在從棧中pop出來,繼續進行當前computed的依賴收集

    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,具體步驟如下:

  • data 屬性初始化 getter setter

  • computed 計算屬性初始化,提供的函式將用作屬性 vm.fullName 的 getter

  • 當首次獲取 fullName 計算屬性的值時,Dep 開始依賴收集

  • 在執行 message getter 方法時,如果 Dep 處於依賴收集狀態,則判定firstNamelastNamefullName  的依賴,並建立依賴關係

  • firstNamelastName 發生變化時,根據依賴關係,觸發 fullName 的重新計算

  • 如果計算值沒有發生變化,不會觸發檢視更新

通過以上的分析,我們知道計算屬性本質上就是一個 computed watcher,也瞭解了它的建立過程和被訪問觸發 getter 以及依賴更新的過程,其實這是最新的計算屬性的實現,之所以這麼設計是因為 Vue 想確保不僅僅是計算屬性依賴的值發生變化,而是當計算屬性最終計算的值發生變化才會觸發渲染 watcher 重新渲染,本質上是一種優化。

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

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

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

周期函式有哪些(beforeCreatedcreated中間都做了什麼

初始化 datapropscomputedwatcherprovide。官方原始碼具體位置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底層原始碼的實現,總體感覺自己回答的還可以,但是面試官說:你應該去阿里...

阿里部門未知(一面)

說說Webpack的實現原理

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

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

首屏優化有哪些解決方案

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

關於懶載入,這裡推薦一篇非常好的文章:Webpack 大法之 Code Splitting。

Node.js的載入機制(requiremodule.exports

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

你覺得你最擅長什麼

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

React和Vue的區別

小提示:這裡React真的好久沒用了,幾乎忘記了,大致說了下單向資料流、雙向資料繫結、資料監聽方式、JSX以及Vue的單檔案元件、函數語言程式設計、Vue的指令之類的。

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

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

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

Vue的響應式原理

什麼情況下會阻塞DOM渲染

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

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

有哪些非同步函式

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

講講MVVM,說說與MVC有什麼區別

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

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

阿里CBU技術部(一面)

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

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

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

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

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

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

熟悉CSS3動畫麼

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

有沒有做過什麼視覺化的專案

小提示:我的回答:地圖算麼?基於OpenLayers設計過地圖的Vue元件庫。

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

你覺得你最擅長的是什麼

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

Flex實現兩列布局

這裡簡單實現一下(其實應該使用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事件流

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

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

小提示:這個如果做過什麼規範或者開發工具之類的,應該比較好回答。

小結

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

阿里企業智慧事業部(一面)

Event Loop

Webpack的loader和plugins的區別

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

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

HTTP狀態碼206是幹什麼的

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

React高階元件的作用有哪些

小提示:好久沒用過React了,大致只知道Racct是單向資料流的,利用高階元件可以實現類似於Vue的雙向資料繫結。

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

React和Vue的區別

Service Worker有哪些作用

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

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

跨域

檔案上傳的二進位制具體是怎麼處理的

小提示:只知道上傳的頭資訊是application/x-www-form-urlencoded,也可以對上傳的檔案的資料進行攔截處理,例如對上傳檔案的資訊進行加密處理。

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

Vue響應式原理

首屏載入效能優化

小結

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

阿里企業智慧事業部(二面)

computed的實現原理

Vue的整個實現原理

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

大家如果想了解Vue原始碼實現的整個粗略過程,可以看下之前寫的文章基於Vue實現一個簡易MVVM/Vue的執行機制簡述。

通訊

小提示:由於這邊涉及到一些海康的裝置(上下位機通訊),面試官問我如何知道上位機軟體給下位機裝置傳送了5次資訊。這個其實大部分Web前端開發在工作上很難遇到類似的問題,辛虧我以前畢業設計中做過上下位機的TCP通訊。後來我從Leader面那裡瞭解到二面面試官應該是做iot物聯網開發這一塊的。

請求幀資料結構如下:

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

Chrome外掛如何遮蔽廣告

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

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

如何判斷兩個變數相等

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

Watch的執行原理

Vue的資料為什麼頻繁變化但只會更新一次

小提示:這裡問的是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的,Dom的更新放在下一個巨集任務或者當前巨集任務的末尾(微任務)中進行執行

由於VUE的資料驅動檢視更新是非同步的,即修改資料的當下,檢視不會立刻更新,而是等同一事件迴圈中的所有資料變化完成之後,再統一進行檢視更新。在同一事件迴圈中的資料變化後,DOM完成更新,立即執行nextTick(callback)內的回撥。

vue和react一樣,對dom的修改都是非同步的。它會在佇列裡記錄你對dom的操作並進行diff操作,後一個操作會覆蓋前一個,然後更新dom。

Event Loop

除了Flex還可以用什麼進行佈局

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

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

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

絕對定位

  • 一旦給元素加上absolutefloat就相當於給元素加上了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層。

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

  • 如果祖先元素是塊級元素,包含塊則設定為該元素的內邊距邊界。

  • 如果祖先元素是行內元素,包含塊則設定為該祖先元素的內容邊界。

問答題:

  • 定位的元素的起始位置為父包含塊的內邊距(不會在border裡,除非使用負值,會在padding裡)

  • 定位的元素的margin還是能起作用的

  • background屬性是會顯示在border裡的

  • z-index是有層疊層級的,需要考慮同一個層疊上下文的層疊優先順序

  • z-index是負值不會覆蓋包含塊的背景色(但是如果有內容,會被包含塊的內容覆蓋)

  • z-index的值影響的元素是定位元素以及flex盒子

  • 上面一個定位元素,下面一個正常流的元素,定位元素會覆蓋在正常流元素之上,除非給z-index是負值

  • 頁面根元素html天生具有層疊上下文,稱之為“根層疊上下文”

小結

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

阿里企業智慧事業部(Leader面)

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

Leader(一)面試

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

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二蠻親切的。

HR面試

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

  • 為什麼要離開現在的公司

  • 以前公司的崗位制度是什麼樣

  • 你是校招進去的麼

  • 你現在的崗位等級情況

  • 你的績效情況

  • 你領導對你的評價是怎麼樣的

  • 領導是不是經常找你溝通

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

  • 你未來對於你的職業有什麼規劃

最後問我還有什麼想問的,我當時已經被三個人問的有點迷迷糊糊了,然後想了想說沒有。

小結

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

企業智慧事業部Leader面後又收到了HR面的面試通知,這一輪面試大致問了以下問題:

  • 你為什麼要離開現在的公司

  • 你們公司的崗位等級是怎麼評定的,你現在是什麼崗位等級

  • 談談你在公司的績效情況

  • 你覺得你做的最有成就感的一件事

  • 你一般解決問題的方法有哪些

  • 你是因為什麼契機選擇做前端

  • 你有對你所在的公司做過什麼流程或制度規範上的改進麼

  • 你最近在看什麼書,和工作相關麼,你為什麼要看這些書

  • 看到你之前還面試了其他兩個部門都掛在了一面,你感覺是什麼原因

  • 你期望的薪資待遇是多少

小提示:這裡HR會問的其實不止這些問題,例如你為什麼喜歡Web前端這個崗位、你未來的職業規劃、你覺得你的優點和缺點有哪些、為什麼選擇阿里巴巴、對之前幾個面試官做下評價、你用過阿里的哪些產品順便談談這些產品的優缺點、你對於網際網路是怎麼理解的...

小結

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

- END -

如果看到這裡,說明你喜歡這篇文章,請轉發、點贊掃描下方二維碼或者微信搜尋「perfect_iscas」,新增好友後即可獲得10套程式設計師全棧課程+1000套PPT和簡歷模板向我私聊「進群」二字即可進入高質量交流群。

掃描二維碼進群↓

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

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

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

在看 阿里p6前端面經(全文3w字)

相關文章