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