
2019年春天我拿到了奇安信的前端開發筆試題當時的第一反應是這家公司考的怎么這么“硬核”。別的公司還在問Vue生命周期和flex布局它已經把手寫深拷貝、事件循環輸出題、XSS防御方案、甚至webpack的plugin機制全部塞進了一張卷子里。做完之后我復盤了很久后來這些年也陸續幫朋友看過不少大廠前端筆試題回過頭再翻開這份試卷很多東西依然有參考價值。這篇文章我會以“過來人”的視角把奇安信2019春招前端開發試題里最典型的幾類考點拆開講清楚為什么考、怎么答才拿分、有什么容易踩的坑。無論你是準備面試的候選人還是負責招聘出題的同行抑或是想夯實基礎的中級前端這篇內容應該都能給你一些啟發。1. 試題整體設計與考察思路1.1 從題型分布看考察方向奇安信2019年春招前端試題的題型整體可以劃分為四類選擇題與填空題、手寫代碼題、簡答題、綜合場景設計題。其中選擇題覆蓋很廣從HTML語義化標簽到TCP三次握手都有涉及但難度不算深主要用來篩掉基礎不牢的人。真正拉開差距的是手寫代碼題和簡答題。那年的筆試題里手寫防抖節流幾乎是必考項深拷貝也出現了。這類題不是讓你默寫而是看你面對邊界條件時能不能想到、能不能處理干凈。我印象里有一道題是問“深拷貝時遇到循環引用會怎樣”很多同學答“會棧溢出”但只有少數人能寫出用WeakMap解決循環引用的方案。這種細節就是閱卷時的分水嶺。1.2 為什么奇安信的題比一般公司“硬”奇安信不是普通互聯網公司它的核心業務是政企安全、數據安全、安全運營平臺。這意味著兩件事第一前端工程師要做大量復雜的管理后臺、可視化大屏、數據報表所以對JavaScript性能和渲染性能有要求第二作為安全公司它對Web安全的理解必須刻進每個崗位的骨子里包括前端。這一點直接反映在試題里比如有一道簡答題是關于XSS的防御方案還出現了“輸入校驗與路徑遍歷”這類帶有安全色彩的考點。普通公司可能把Web安全放在加分題里奇安信直接把它放在必答題里。我當時做完就有一種感覺這不是單純招前端而是在招“懂安全的前端”。所以如果你準備投這類安全公司web安全基礎、前端安全編碼習慣一定不能裸考。2. 核心考點拆解JavaScript基礎與進階2.1 原型鏈與this指向問題原型鏈和this指向在2019年的前端面試里屬于“保留曲目”奇安信也不例外。它出現在一道選擇題里給出一段代碼讓選出輸出結果代碼大概長這樣function Foo() { this.value 1; } Foo.prototype.getValue function() { return this.value; }; const foo new Foo(); const getValue foo.getValue; console.log(getValue());這題的核心考點有兩個第一this的綁定規則——getValue是作為普通函數調用的此時this指向window或undefined取決于是否為嚴格模式而不是foo第二Foo.prototype上的方法本質上就是普通函數它的this不天然綁定到實例上。答題時建議按“四步走”思路先判斷調用方式再套綁定規則然后考慮嚴格模式影響最后確認輸出。很多人在這題上栽跟頭是因為把“方法定義在原型上”和“方法調用時綁定this”兩件事混淆了。我自己的經驗是做這種題不要背結論要練習用規則推導。2.2 事件循環與異步編程順序異步編程的考察主要是讓你預測一組setTimeout、Promise、async/await的輸出順序。比如console.log(1); setTimeout(() console.log(2), 0); Promise.resolve().then(() console.log(3)); async function test() { console.log(4); await Promise.resolve(); console.log(5); } test(); console.log(6);大部分人會答成“1、4、6、2、3、5”而正確順序是“1、4、6、3、5、2”。這里的關鍵在于await后面跟著的Promise.resolve()會生成微任務但await本身會立即讓出執行權所以后面的console.log(5)是等微任務執行完才運行的而微任務又優先于宏任務。這個考點考察的其實不是背結論而是對事件循環機制的理解。如果要展開講宏任務和微任務的執行規則可以畫成一句話每執行完一個宏任務都會清空整個微任務隊列再進入下一個宏任務。答題時如果能順帶提一句Node.js和瀏覽器在事件循環實現上的差異那會是一個不錯的加分點。2.3 手寫代碼題防抖、節流、深拷貝、Promise.all手寫題是奇安信筆試的“重頭戲”。當年比較常見的是防抖和節流現在幾乎已經是前端面試的標配了但放在2019年能寫得干凈利落的人比例并不高。防抖的核心是設置一個定時器在連續觸發時重置時間保證最后一次觸發后等待一段時間才執行function debounce(fn, delay 300) { let timer null; return function (...args) { if (timer) clearTimeout(timer); timer setTimeout(() { fn.apply(this, args); }, delay); }; }節流的常見實現是時間戳版本或定時器版本。我在答題時一般寫定時器版本因為它更好理解function throttle(fn, interval 300) { let timer null; return function (...args) { if (timer) return; timer setTimeout(() { fn.apply(this, args); timer null; }, interval); }; }這里容易忽略的點有兩個一是this的透傳用了apply才能讓原函數在正確的上下文里執行二是防抖和節流的使用場景面試官很可能追問“什么時候用防抖什么時候用節流”我的習慣是答“輸入框實時搜索、按鈕重復提交用防抖滾動監聽、拖拽、resize用節流”。深拷貝這個題也是必背內容但真正高分答案要處理這些邊界Date、RegExp、Symbol、函數、循環引用。function deepClone(obj, hash new WeakMap()) { if (obj null || typeof obj ! object) return obj; if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags); if (hash.has(obj)) return hash.get(obj); const clone Array.isArray(obj) ? [] : {}; hash.set(obj, clone); for (const key of Object.keys(obj)) { clone[key] deepClone(obj[key], hash); } return clone; }注意這里用了WeakMap而不是Map因為WeakMap的鍵是弱引用不會造成內存泄漏。循環引用是關鍵場景var a {}; a.self a;如果不做緩存處理遞歸會無限循環導致棧溢出。這個邊界條件2019年的考卷上如果寫出來了基本就是滿分思路。3. 瀏覽器端必考渲染機制與性能優化3.1 從輸入URL到頁面展示的完整鏈路奇安信的前端考題里有一類“串鏈路”題讓你描述從輸入URL到頁面展示的完整過程。這種題考察的是知識樹的完整性DNS解析、HTTP請求建立、服務器響應、瀏覽器解析渲染每一步都可以深挖。我當時回答時把過程分成四段DNS解析域名拿到IP通過TCP三次握手建立連接如果是HTTPS還要加上TLS握手協商密鑰瀏覽器發起HTTP請求服務器返回HTML、CSS、JavaScript瀏覽器解析HTML構建DOM樹解析CSS構建CSSOM樹兩者合成渲染樹經過布局和繪制后呈現在頁面上。如果頁面里有圖片、JavaScript還要考慮并發加載和阻塞解析的問題。答題時有個加分細節渲染過程中script標簽會阻塞DOM解析所以需要把腳本放在/body前或者加defer/async屬性。這個點看似基礎但結合后面的性能優化題來回答就能讓閱卷人看出你理解的是“為什么”而不是“背答案”。3.2 回流、重繪與合成奇安信考題中關于性能的題目很多會落到“回流reflow與重繪repaint”上。比如有一道題問為什么用transform做動畫比修改top/left性能好答案不只是“transform不會觸發回流”更準確的說法是transform會觸發合成層動畫過程在合成線程完成不涉及主線程的布局和繪制。答題時我建議把瀏覽器渲染管線列出來DOM樹構建 → 樣式計算Style → 布局Layout → 繪制Paint → 合成Composite。如果修改left會觸發 Layout 和 Paint后續每一步都要重新執行如果修改transform只是改變合成層的位置Paint 和 Layout 都能跳過所以更流暢。為了體現深度可以補一句減少回流還可以通過批量修改樣式、使用documentFragment或先把元素設為display: none再進行DOM操作。這些技巧本身就是性能優化題的答案素材。3.3 線上數據大屏的性能優化切入點結合奇安信的業務場景數據可視化大屏很可能是日常開發中繞不開的模塊。我在實際做這類項目時有一個體會大量圖表同時渲染時性能瓶頸往往不在繪圖本身而在數據的處理和DOM的更新方式。常用的優化策略包括圖表按需渲染而不是一次性渲染全部把圖表實例的setOption操作合并減少不必要的重繪利用requestAnimationFrame控制更新頻率大數據量時用canvas而不是svg。答題時如果能把性能和業務場景結合起來比如“安全運營中心的告警大屏如果有上萬條告警同時滾動更新應該怎么做優化”那就能體現出你在真實項目中思考過而不是只會背概念。4. 前端安全方向安全公司的獨特考察點4.1 XSS的類型與防御措施奇安信作為安全公司前端試題里出現XSS太正常了。這類題通常會讓描述XSS的分類以及各自的防御方案。XSS包含三大類存儲型、反射型、DOM型。區分它們的關鍵是惡意腳本的來源和注入位置存儲型和反射型都是服務端漏洞只是存儲型是持久化的反射型是拼接在URL參數里的DOM型則是前端JavaScript直接操作DOM時造成的。防御措施要從多個層面作答。輸出編碼是第一步對不同上下文HTML標簽、屬性、JavaScript、CSS做對應編碼使用CSP內容安全策略限制腳本來源設置HttpOnly防止Cookie被腳本竊取。我當年吃到虧的一點是只回答了“過濾輸入和轉義輸出”忽略了CSP。閱卷人如果說“僅靠過濾是不夠的”那其實是在提示你XSS的防御必須站在縱深防御的角度不能靠單一的防護手段這個思路是答安全題的底層邏輯。4.2 CSRF的攻擊流程與token機制CSRF跨站請求偽造也是安全題的常客。理解CSRF的前提是明白瀏覽器的一個行為只要Cookie沒過期請求會自動帶上它。所以攻擊者可以構造一個看似合法的請求誘導用戶在不知情的情況下提交到目標站點。防御手段中的核心是CSRF Token機制服務端在頁面渲染時生成一個隨機token前端發起請求時帶上這個token服務端校驗。需要注意的是現在很多項目也依賴SameSiteCookie 屬性來緩解CSRF比如配置SameSiteLax但我會建議在答題時說明它的限制——有些跨站場景依然無法完全覆蓋。奇安信的題中如果出現CSRF很可能還會追問“前端在CSRF防御中能做什么”。常規答案是在請求頭中手動加入自定義字段服務端校驗該字段因為瀏覽器跨域時帶自定義header會觸發預檢請求攻擊者無法在不經過預檢的情況下成功發起惡意請求。4.3 輸入校驗與路徑遍歷的隱患熱詞列表里有“輸入驗證路徑遍歷”這樣的關鍵詞說明當年的試題甚至包含了一些偏后端的安全概念。路徑遍歷Path Traversal是指攻擊者通過構造包含../的路徑來訪問服務器上的任意文件比如../../../etc/passwd。雖然這是偏后端的漏洞但前端也可能參與其中。如果前端允許用戶上傳文件或輸入文件路徑并且直接傳給后端處理就要考慮路徑規范化的問題。答題時可以提到前端要對用戶輸入做白名單校驗禁止包含../或絕對路徑等危險信息更重要的后端必須做最終的路徑規范化不能被前端的校驗替代。這一題給我們的啟示是安全公司的前端面試會考察你是否具備“安全開發”的全局視角而不僅僅是頁面寫得好不好。5. 框架與工程化Vue 2與webpack5.1 Vue 2響應式原理與虛擬DOM2019年Vue 2還是絕對主流奇安信的試題里也考了Vue 2的響應式原理。核心考察點是Object.defineProperty如何使用以及它的兩個短板無法監聽數組的變化需要通過重寫數組方法解決、無法監聽對象屬性的新增和刪除需要使用Vue.set和Vue.delete。答題時建議按“數據劫持 → 依賴收集 → 派發更新”的邏輯講組件渲染時每個數據對象的屬性都有對應的Dep組件渲染會觸發屬性的getter把 Watcher 收集起來數據變化時觸發setter通知所有依賴它的 Watcher 更新。虛擬DOM的價值在于數據變化后不直接操作真實DOM而是通過 diff 計算出真正需要修改的部分。如果面試官追問 key 的作用可以這樣答key 主要用來標識節點身份幫助 diff 算法判斷節點是復用還是重建。列表順序變化時如果沒有唯一keydiff 會認為節點類型沒變但內容變了會執行很多無謂的更新加上 key 之后Vue 可以精確地移動或復用節點。5.2 webpack loader與plugin的區別工程化方向奇安信2019年的試題里出現過“loader和plugin的區別”這種基礎概念題。loader是文件轉換器比如把 ES6 轉成 ES5把 Vue 單文件組件轉成 JavaScript 模塊plugin則是在webpack整個構建過程的特定時機執行擴展邏輯比如HtmlWebpackPlugin會在輸出階段自動生成HTML文件。回答這個問題可以舉一個落地的例子項目里需要把資源路徑加上CDN前綴這個時候用output.publicPath配置即可但如果我們還想在構建完成后把多余的文件清理掉就需要CleanWebpackPlugin這種plugin來處理整個輸出流程。整理成一句話loader作用在“文件”級別plugin作用在“流程”級別。構建優化方面當年比較常用的是happypack或thread-loader做多線程打包、DllPlugin預編譯公共庫、purgecss做無用CSS清理。現在webpack版本已經迭代很多次但這些思路依然有效——優化的本質無非是緩存、并發、按需引入、減少搜索范圍這幾類。5.3 前端工程化代碼規范與項目骨架奇安信的業務大多涉及政企客戶代碼質量要求會比一般To C公司更高。這在試題中也隱約體現出來會有簡答題問“你們項目的代碼規范是怎么落地的”或者“Vue項目如何組織目錄結構更利于維護”。這個問題沒有標準答案但答題時要能說出具體的工具鏈和執行流程。比如用 ESLint Prettier husky lint-staged 的組合在 commit 前自動對暫存區的代碼做校驗和格式化能有效保證多人協作時風格統一。再比如目錄結構上按模塊劃分業務代碼把公共組件、頁面、狀態管理、工具函數分開同時通過別名避免深層相對路徑的混亂。真實項目中這些工具組合的落地并不簡單。ESLint 和 Prettier 的規則如果不提前統一會出現沖突husky 安裝后需要配置 Hooks 路徑lint-staged 如果配置過濾條件寫錯可能直接把所有文件都跑一遍。這些細節在作答時提一下會讓面試官覺得你不是只會寫demo。6. 常見問題與答題技巧實錄6.1 答題順序與時間分配策略奇安信2019春招的筆試題量不小我記得現場做題的時候時間是比較緊的。我的經驗是先快速瀏覽所有題目優先做“一眼就知道答案”的選擇題和填空題把該拿的分先拿穩然后做手寫代碼題這類題分值高即使寫不全也能拿步驟分最后再做簡答題和場景設計題。有些同學容易在簡答題上花太多時間試圖把每個概念都寫得非常完美結果后面的手寫題沒有時間做。手寫題的分數權重通常更高寫出一版可運行的防抖函數比把XSS原理寫三段更有用。所以如果時間不夠簡答題可以答要點、列出關鍵詞不要糾結措辭。6.2 筆試中常見的丟分點復盤從我自己和后來幫同學復盤的情況看丟分點主要集中在幾個地方。手寫防抖節流時忘記處理this和args導致原函數在錯誤上下文執行深拷貝只處理普通對象和數組沒考慮循環引用直接棧溢出事件循環輸出題沒有區分微任務和宏任務尤其是await后面的代碼執行時機Vue響應式題目用了新術語“Proxy”解釋但對 Object.defineProperty 的局限說得不夠清楚webpack題把loader和plugin混為一談這在閱卷時是非常明確的扣分點。丟分并不可怕可怕的是不知道自己丟在哪。我一般建議候選人這樣自查做完筆試題后不要急著交卷把每道題的答案在腦子里過一遍如果是代碼題試著把變量名、邊界條件重新讀一遍很多低級錯誤能在這一步被發現。6.3 面試現場追問與溝通技巧筆試題只是第一關后面的技術面通常會圍繞筆試內容展開追問。我就遇到過這樣的情況筆試寫了防抖函數面試官追問“如果我想讓節流第一次觸發時立即執行應該怎么寫”這實際上是在考你對節流背后的開關機制是否理解而不是只看你是否背出了代碼。我的建議是面試時不要背誦答案而是用“問題拆解”的方式回答。先說思路再講實現最后補充邊界條件的處理。哪怕某個知識點記不全也可以說“我記得大致原理是XX但具體API我有些記不清了能不能讓我再想想”。坦誠比假裝自信更受認可尤其是在技術面試這個場景下。奇安信這類安全公司的面試官通常比較看重候選人的“安全感”。所謂“安全感”就是回答問題的時候你讓面試官覺得你的知識邊界是清晰的哪些是你確定的哪些你了解過但沒用過哪些完全不會你能說清楚。這一點往往比一道題的答案完整還要加分。6.4 綜合場景題安全信息系統的前端架構奇安信的試題里還有一種讓我印象深刻的場景題假設我們要做一個安全運營中心的管理系統模塊包括告警列表、用戶權限管理、大屏展示、報表導出請描述前端的整體架構方案。這種題沒有標準答案但考核點非常明確——有沒有全局思維。我當時是分四個維度回答的工程層面使用Vue全家桶按業務模塊劃分路由和store組件庫用ElementUI做二次封裝權限層面前端路由守衛加動態路由結合用戶角色配置菜單和操作按鈕后端接口同樣校驗權限數據層面列表數據使用分頁和懶加載大屏數據通過WebSocket推送增量更新報表下載用Blob處理流文件安全層面對導出接口返回的數據做校驗防止越權導出前端對用戶的輸入做白名單管控并對富文本內容做XSS轉義。這種回答的價值在于它讓面試官看到你能把一個復雜系統拆解成可落地的執行方案而不是只會寫局部代碼。后來我做技術評審和招聘時也會用這道題來考察候選人的系統設計能力。個人經驗收尾回頭再看奇安信2019春招這套題它其實代表了一類“技術向業務向”結合的出題風格基礎題考功底原理題考深度安全題考行業理解場景題考全局視野。它不簡單但也是真的能篩出人。我在實際工作中最大的體會是面試題里那些花里胡哨的知識點最后都會落在日常開發的瑣碎里。比如你理解了深拷貝的循環引用就會在寫緩存工具時想到WeakMap你理解事件循環就不會再把所有異步問題都用setTimeout糊弄過去你理解XSS的深層原理就不會隨便在業務代碼里拼HTML字符串。所以我的建議很簡單不管是準備面試還是日常提升別把時間都花在刷“題目印象”上。把奇安信這套試題當作一個知識體檢單逐項檢查自己哪些是真懂、哪些只是聽說過然后回到原理層面補課。基礎這層護城河挖得越深越不會被替代。