在過(guò)去的幾年里,我在亞馬遜和雅虎面試過(guò)很多專注于前端開(kāi)發(fā)的 Web 開(kāi)發(fā)者和軟件工程師,在這篇文章中,我想分享一些面試技巧,幫助候選人為面試做好準(zhǔn)備。
免責(zé)聲明——本文并非旨在列出在前端面試中可能會(huì)被問(wèn)到的所有問(wèn)題,但可以將其視為知識(shí)的基線。
通過(guò)面試不是件容易的事,作為候選人,通常需要在 45 分鐘的時(shí)間內(nèi)展示自己能做些什么。作為一名面試官,同樣難以在這么短的時(shí)間內(nèi)評(píng)估候選人是否適合。對(duì)于面試來(lái)說(shuō),并不存在一刀切的方法,面試官問(wèn)的問(wèn)題通常會(huì)有一個(gè)范圍,但除此之外,他們可以自行決定要問(wèn)哪些其他問(wèn)題。
作為曾經(jīng)的候選人和面試官,我試圖在這篇文章中涵蓋你可能會(huì)在面試中被問(wèn)到的最重要的前端開(kāi)發(fā)知識(shí)。
常見(jiàn)的誤解
我見(jiàn)過(guò)候選人犯的最大錯(cuò)誤之一就是準(zhǔn)備了一些瑣碎的問(wèn)題,例如“什么是盒子模型”或者“JavaScript 中的 ?==
? 和 ?===
? 之間的區(qū)別是什么”。知道這些問(wèn)題的答案固然是好,但這并不會(huì)告訴面試官來(lái)太多有用的信息。
相反,在實(shí)際的面試中,你可能需要使用 JavaScript、CSS 和 HTML 來(lái)編寫(xiě)代碼。在你的面試期間,你可能需要實(shí)現(xiàn) UI、構(gòu)建窗口小部件或使用 Lodash 和 Underscore.js 這樣的庫(kù)編寫(xiě)常用的實(shí)用程序函數(shù)。例如:
- 構(gòu)建常見(jiàn)的 Web 應(yīng)用程序的布局和交互,例如類似 Netflix 網(wǎng)站那樣的。
- 實(shí)現(xiàn)小部件,如日期選擇器、輪播或電子商務(wù)網(wǎng)站購(gòu)物車。
- 寫(xiě)一個(gè)類似 ?
debounce
? 或深度 ?clone
? 對(duì)象的函數(shù)。
說(shuō)到庫(kù),我看到候選人經(jīng)常犯的另一個(gè)錯(cuò)誤是他們需要完全依賴最新的框架來(lái)解決面試問(wèn)題。你可能會(huì)想,如果我可以在生產(chǎn)環(huán)境中使用 jQuery、React、Angular 等,那為什么就不能在面試中使用它們呢?技術(shù)、框架和庫(kù)會(huì)隨著時(shí)間的推移而發(fā)生變化——我更感興趣的是你是否了解前端開(kāi)發(fā)的底層原理,而不是依賴更高層次的抽象。如果你不能在沒(méi)有它們的情況下回答面試問(wèn)題,我希望你至少可以徹底解釋和推測(cè)這些庫(kù)背后的原理。
總的來(lái)說(shuō),大部分的面試都涉及實(shí)際的編碼。
JavaScript
你需要了解 JavaScript,而且是徹底地了解。你面試的職位越高,對(duì)語(yǔ)言知識(shí)的要求就越高。以下是你應(yīng)該熟悉的 JavaScript 知識(shí)點(diǎn):
- 執(zhí)行上下文,尤其是詞法作用域和閉包;
- 提升、函數(shù)和塊作用域,以及函數(shù)表達(dá)式和聲明;
- 綁定——特別是 ?
call
?、?bind
?、?apply
? 和 ?this
?; - 對(duì)象原型、構(gòu)造函數(shù)和 ?
mixin
?; - 組合和高階函數(shù);
- 事件委托和冒泡;
- 使用 ?
typeof
?、?instanceof
?和 ?Object.prototype.toString
? 進(jìn)行類型轉(zhuǎn)換; - 使用回調(diào)、?
promise
?、?await
? 和 ?async
? 處理異步調(diào)用; - 什么時(shí)候可以使用函數(shù)聲明和表達(dá)式。
DOM
知道如何遍歷和操作 DOM 非常重要,對(duì)于重度依賴 jQuery 或者開(kāi)發(fā)了很多 React & Angular 類型應(yīng)用程序的候選人來(lái)說(shuō),他們可能會(huì)在這個(gè)問(wèn)題上栽跟斗。你可能不會(huì)每天都直接接觸 DOM,因?yàn)槲覀兇蠖鄶?shù)人都在使用各種抽象。在不使用第三方庫(kù)的情況下,你需要知道如何執(zhí)行以下這些操作:
- 使用 ?
document.querySelector
? 選擇或查找節(jié)點(diǎn),在舊版瀏覽器中使用 ?document.getElementsByTagName
?; - 上下遍歷——?
Node.parentNode
?、?Node.firstChild
?、?Node.lastChild
? 和 ?Node.childNodes
?; - 左右遍歷——?
Node.previousSibling
?和 ?Node.nextSibling
?; - 操作——在 DOM 樹(shù)中添加、刪除、復(fù)制和創(chuàng)建節(jié)點(diǎn)。你應(yīng)該了解如何修改節(jié)點(diǎn)的文本內(nèi)容以及切換、刪除或添加 CSS 類名等操作;
- 性能——當(dāng)有很多節(jié)點(diǎn)時(shí),修改 DOM 的成本會(huì)很高,你至少應(yīng)該知道如何使用文檔片段和節(jié)點(diǎn)緩存。
CSS
至少,你應(yīng)該知道如何在頁(yè)面上布局元素,如何使用子元素或直接后代選擇器來(lái)定位元素,以及什么時(shí)候該用類、什么時(shí)候該用 ID。
- 布局——安排彼此相鄰的元素的位置,以及如何將元素布置成兩列或三列;
- 響應(yīng)式設(shè)計(jì)——根據(jù)瀏覽器寬度大小更改元素的尺寸;
- 自適應(yīng)設(shè)計(jì)——根據(jù)特定斷點(diǎn)更改元素的尺寸;
- 特異性——如何計(jì)算選擇器的特異性,以及級(jí)聯(lián)如何影響屬性;
- 適當(dāng)?shù)拿臻g和類命名。
HTML
知道哪些 HTML 標(biāo)簽最能代表你正在顯示的內(nèi)容以及相關(guān)屬性,應(yīng)該掌握手工知識(shí)。
- 語(yǔ)義標(biāo)記;
- 標(biāo)記屬性,例如 ?
disabled
?、?async
?、?defer
? 以及何時(shí)使用 ?data-*
?; - 知道如何聲明 ?
doctype
?(大多數(shù)人不是每天都會(huì)寫(xiě)新頁(yè)面,所以可能會(huì)忘了這個(gè))以及可以使用哪些元標(biāo)簽; - 可訪問(wèn)性問(wèn)題,例如,確保輸入復(fù)選框具有更大的響應(yīng)區(qū)域(使用標(biāo)簽“?
for
?”)。另外還有 ?role="button"
?、?role="presentation"
?,等等。
系統(tǒng)設(shè)計(jì)
在系統(tǒng)設(shè)計(jì)方面,通常涉及 MapReduce、分布式鍵值存儲(chǔ)系統(tǒng)或 CAP 定理等知識(shí)。雖然前端工程師日常不需要深入了解如何設(shè)計(jì)這類系統(tǒng),但在被要求設(shè)計(jì)出常見(jiàn)應(yīng)用程序的前端架構(gòu)時(shí),你也不應(yīng)該感到驚訝。這些問(wèn)題通常含糊不清,比如“設(shè)計(jì)一個(gè)像 Pinterest 這樣的網(wǎng)站”或者“如何構(gòu)建購(gòu)物結(jié)賬服務(wù)?”。以下是需要考慮的知識(shí)點(diǎn):
- 渲染——客戶端渲染(CSR)、服務(wù)器端渲染(SSR)和全局渲染;
- 布局——如果你正在設(shè)計(jì)被多個(gè)開(kāi)發(fā)團(tuán)隊(duì)使用的系統(tǒng),需要考慮進(jìn)行組件化,以及是否需要開(kāi)發(fā)團(tuán)隊(duì)通過(guò)指定標(biāo)記來(lái)使用組件;
- 狀態(tài)管理,例如在單向數(shù)據(jù)流或雙向數(shù)據(jù)綁定之間做出選擇。你還應(yīng)該考慮你的設(shè)計(jì)是采用被動(dòng)式還是反應(yīng)式編程模型,以及組件如何相互關(guān)聯(lián),例如是 Foo->Bar 還是 Foo->Bar;
- 異步——你的組件可能需要與服務(wù)器進(jìn)行實(shí)時(shí)的通信。在設(shè)計(jì)時(shí)需要考慮使用 XHR 或雙向調(diào)用。如果你的面試官要求你支持舊瀏覽器,那么你需要在隱藏 iFrame、script 標(biāo)簽或 XHR 之間做出選擇。如果沒(méi)有,你可以建議使用 websocket,或者使用服務(wù)器發(fā)送事件(SSE),這樣會(huì)更好;
- 關(guān)注點(diǎn)分離——Model-View-Controller(MVC)、Model-View-ViewModel(MVVM)和 Model-View-Presenter(MVP)模式;
- 多設(shè)備支持——你的實(shí)現(xiàn)是否同時(shí)支持 Web、移動(dòng) Web 和混合應(yīng)用程序,還是為每一種場(chǎng)景提供單獨(dú)的實(shí)現(xiàn)?如果你正在構(gòu)建像 Pinterest 這樣的網(wǎng)站,你可能會(huì)考慮在 Web 上使用三列,但在移動(dòng)設(shè)備上只使用一列,你的設(shè)計(jì)將如何處理這個(gè)問(wèn)題;
- 資產(chǎn)文件交付——在大型應(yīng)用程序中,獨(dú)立團(tuán)隊(duì)擁有自己的代碼庫(kù)是常有的事。這些不同的代碼庫(kù)可能彼此依賴,每個(gè)代碼庫(kù)通常都有自己的管道來(lái)發(fā)布代碼變更。你的設(shè)計(jì)需要考慮如何基于依賴項(xiàng)進(jìn)行資產(chǎn)文件的構(gòu)建(代碼拆分)、測(cè)試(單元測(cè)試和集成測(cè)試)和部署。你還需要考慮如何通過(guò) CDN 交付資產(chǎn)文件或者內(nèi)聯(lián)它們來(lái)減少網(wǎng)絡(luò)延遲。
Web 性能
除了通用編程最佳實(shí)踐之外,你應(yīng)該期望訪問(wèn)者查看你的代碼或設(shè)計(jì)及其性能影響。它曾經(jīng)足以將 CSS 置于文檔的頂部,而 JS 腳本位于頁(yè)面底部,但 Web 正在快速移動(dòng),你應(yīng)該熟悉這個(gè)領(lǐng)域的復(fù)雜性。
- 關(guān)鍵渲染路徑;
- Service Worker;
- 圖像優(yōu)化;
- 延遲加載和捆綁拆分;
- HTTP/2 和服務(wù)器推送的一般含義;
- 何時(shí)預(yù)取和預(yù)加載資源;
- 減少瀏覽器回流以及何時(shí)將元素提升到 GPU;
- 瀏覽器布局、組合和繪制之間的區(qū)別。
數(shù)據(jù)結(jié)構(gòu)和算法
這個(gè)可能有點(diǎn)爭(zhēng)議,但對(duì) Big-O 時(shí)間復(fù)雜性和常見(jiàn)運(yùn)行時(shí)間(如 O(N) 和 O(N Log N))有一個(gè)基本的了解對(duì)你來(lái)說(shuō)不會(huì)是壞事。單頁(yè)應(yīng)用程序現(xiàn)在非常常見(jiàn),所以了解內(nèi)存管理等方面的知識(shí)是有幫助的。例如,如果你被要求構(gòu)建客戶端拼寫(xiě)檢查程序,那么了解常見(jiàn)的數(shù)據(jù)結(jié)構(gòu)和算法將會(huì)讓你的任務(wù)變得輕松許多。
我不是說(shuō)你一定需要念一個(gè)計(jì)算機(jī)學(xué)位,但這個(gè)行業(yè)已經(jīng)從構(gòu)建簡(jiǎn)單的網(wǎng)頁(yè)轉(zhuǎn)移到了計(jì)算機(jī)科學(xué)。網(wǎng)上有很多資源可以讓那個(gè)你快速掌握基礎(chǔ)知識(shí)。
一般的 Web 知識(shí)
你需要掌握一些構(gòu)成 Web 的技術(shù)和范式。
- HTTP 請(qǐng)求——GET 和 POST 以及相關(guān)標(biāo)頭,如 Cache-Control、ETag、Status Codes 和 Transfer-Encoding;
- REST 與 RPC;
- 安全性——何時(shí)使用 JSONP、COR 和 iFrame。
總結(jié)
對(duì) Web 開(kāi)發(fā)人員或工程師來(lái)說(shuō),構(gòu)建 Web 應(yīng)用程序需要掌握大量的知識(shí)。不要被知識(shí)的深度所限制,而是要保持開(kāi)放的心態(tài)去學(xué)習(xí)所有復(fù)雜的部分。
除了這里涉及的技術(shù)主題之外,你還需要討論過(guò)去參與的項(xiàng)目,描述發(fā)生了哪些有趣的事情以及做出了哪些權(quán)衡。
文章出處 | 前端之巔
想要學(xué)習(xí)更多編程知識(shí)請(qǐng)前往 W3Cschool官網(wǎng),隨時(shí)隨地學(xué)編程。