
愛奇藝2019秋招前端方向筆試題A在網上已經傳了好幾年但每次拿出來看都不過時。原因很簡單這份卷子考的不是“背答案”而是前端基礎功底的扎實程度以及遇到陌生問題時怎么拆解、怎么推導。我自己在做這份題的過程中最大的感受就是——它把JS的語言特性、瀏覽器運行機制、CSS布局原理、網絡協議常識、代碼手寫能力這幾個維度全部串在了一起。如果你正在準備大廠前端崗的筆試或者已經工作但想系統復盤一下基礎這份題都是一個很好的試金石。這篇內容我會按照筆試題的高頻模塊來拆解把每類題目背后的考點、原理、踩坑點都展開講最后附上一些實戰經驗。1. 內容整體設計與思路拆解1.1 核心考點拆解愛奇藝這套前端筆試題A的考察范圍基本可以映射到大多數中大型互聯網公司前端筆試的經典結構JavaScript語言特性、CSS布局與渲染、瀏覽器與網絡、手寫代碼與邏輯題。它不會直接問“閉包是什么”這種八股而是通過讀代碼寫輸出、補全代碼、判斷執行順序等方式考察你是否真正理解這些特性。這套卷子里最值得注意的是把“輸出順序題”和“原型/繼承題”作為重點。這類題在牛客網上特別常見但很多人刷題只是記答案不去追“為什么”。比如一道經典的setTimeout與Promise輸出順序題如果你不理解微任務和宏任務的執行時機、不理解事件循環的每一輪都會“先清空微任務隊列”那換一個變體就必錯。愛奇藝的題也有這個風格喜歡在細節上做文章一個選項里的小括號位置都會影響整個邏輯。另外CSS部分不會直接考“flex怎么用”而是給一個布局需求讓你寫屬性或者給你一段代碼問最終渲染居中還是歪了。這說明考點是“實際場景下能不能正確地使用屬性”不是背單詞。而 HTML 語義化、BFC、層疊上下文這些雖然老但依然會反復出現——因為這些直接決定了頁面的可維護性和渲染表現。1.2 為什么大廠筆試偏愛這類題型很多人疑惑前端平時寫業務都是 Vue/React為什么筆試不考框架核心原因是框架迭代太快語言和瀏覽器才是恒定的底層。Vue 3 的源碼、React 的調度機制本質上都是基于 JS 語言特性和瀏覽器 API 來實現的。如果一個候選人連var和let的區別、和的轉換規則都說清楚那讓他上手框架也得靠猜。愛奇藝作為視頻巨頭前端團隊要面對播放器、首屏渲染、流量控制、廣告投放、頁面性能優化等高復雜度場景。這些場景非常依賴對事件循環、DOM 操作代價、緩存策略、網絡請求調度的深入理解。所以筆試出題方向天然偏向這些基礎能力。同時筆試題也篩掉“只會調接口寫頁面”的候選人。前端崗位的競爭早就白熱化了單純會“調庫”“會用組件”已經不夠。企業需要一個候選人能解釋“為什么頁面卡”、能定位“為什么這個按鈕點擊后延遲反饋”、能設計“如何減少不必要的渲染”。這些全得靠基礎功底。所以做這份題與其說是應付面試不如說是一次自我體檢。2. 核心細節解析與實操要點2.1 JavaScript 基礎考點從執行上下文到閉包JS 部分最核心的幾塊執行上下文與作用域鏈、閉包、this 指向、原型鏈、Event Loop、ES6 新特性。愛奇藝這類大廠筆試很少直接考概念更多是給代碼問輸出所以關鍵是要學會“模擬執行過程”。一個常見題型是var a 1; function foo() { console.log(a); var a 2; } foo();輸出是什么答案是undefined。原因是var聲明會提升到函數作用域頂部所以函數內的a在打印時已經被定義但還沒有賦值。這就叫變量提升。很多人只看答案覺得簡單但換成let就會變成ReferenceError因為let存在暫時性死區TDZ。閉包題往往結合循環for (var i 0; i 3; i) { setTimeout(function() { console.log(i); }, 100); }輸出是3 3 3。原因是var沒有塊級作用域setTimeout回調里訪問的是同一個i而循環結束時i已經是 3。把var改成let或者用 IIFE、bind、閉包包一層才能輸出0 1 2。這背后實際上就是作用域捕獲的時機問題也是筆試里最常設的坑。關于 this 指向我給大家一個最實用的判斷口訣“函數被誰調用this 就指向誰”。但還要記住例外箭頭函數沒有自己的 this它繼承外層詞法作用域的 thisnew調用的時候 this 指向新對象call/apply/bind可以顯式指定 this。筆試題里最常見的套路是var obj { name: a, fn: function() { console.log(this.name); } }; var f obj.fn; f();這段輸出undefined嚴格模式下或全局對象屬性而不是a。因為f()調用時調用者是全局對象不是obj。這類題考察的是“引用丟失”問題在 React 類組件時代經常出現現在寫函數組件也偶爾會遇到類似場景。2.2 CSS 與瀏覽器渲染盒模型、BFC、層疊上下文CSS 部分不能只靠“用過 flex”。筆試題會重點考察標準盒模型和 IE 盒模型的區別、外邊距折疊、BFC 的形成條件與作用、層疊上下文、水平垂直居中方案、flex 的 flex-grow/shrink 計算。盒模型這道基礎題每次筆試出現率都極高。box-sizing: content-box時width只算內容寬度border-box時width包含內容、內邊距和邊框。實際開發時設置全局* { box-sizing: border-box; }可以減少大量寬高計算麻煩。這一點在筆試題里往往通過“問某個元素的實際占位寬度”來考。BFC 是一塊硬骨頭但記住“BFC 是一個獨立的渲染區域內外互相不影響”就抓住了本質。觸發 BFC 的條件很多float不為none、overflow不為visible、display: inline-block、position: absolute/fixed、display: flex等。用途主要是清除浮動、防止外邊距折疊、阻止元素被浮動元素覆蓋。比如經典的“父元素高度塌陷”問題給父元素設置overflow: hidden觸發 BFC就能把浮動子元素的高度算進去。層疊上下文則容易和z-index混淆。實際上z-index只在相同層疊上下文中比較。transform、opacity、filter、position加z-index都會創建層疊上下文。筆試題常給一個多層嵌套的定位元素問你哪個在最上面這時候就要按“父級上下文先比再比同級的 z-index”來推。我見過不少人死記z-index: 9999碰到嵌套場景還是出錯關鍵是理解規則。2.3 瀏覽器與網絡HTTP 緩存機制前端筆試里網絡部分的常客是TCP 握手、HTTP 狀態碼、GET/POST 區別、HTTP 緩存、跨域。愛奇藝這套題里同樣有涉及尤其是緩存。HTTP 緩存可以簡單理解為“服務器給資源打標簽瀏覽器下次按標簽決定是否復用”。強緩存階段瀏覽器直接用本地副本不請求服務器協商緩存階段瀏覽器帶著標簽去問服務器“這個資源還能用嗎”服務器決定返回304還是新資源。相關字段有Cache-Control: max-age、Expires強緩存Last-Modified/If-Modified-Since、ETag/If-None-Match協商緩存。前端筆試特別愛問“輸入 URL 到頁面展示的全過程”。這不是背流程就行而是要說明每一步的關鍵機制DNS 解析可能會查緩存、TCP 連接三次握手、發送 HTTP 請求攜帶緩存校驗信息、服務器返回響應、瀏覽器解析 HTML 構建 DOM 樹、解析 CSS 構建樣式規則、JS 阻塞解析、布局與繪制。能流暢說出這個過程說明你對瀏覽器運行機制有整體概念這也是性能優化思路的起點。2.4 手寫代碼與算法從數組去重到防抖節流手寫題是筆試中的重頭戲。最常出現的幾類數組去重、數組扁平化、深拷貝、防抖節流、Promise 實現、函數柯里化、Pub/Sub 事件總線。愛奇藝這類題的特點是要求不一定用 ES6 一行流而是看你能不能寫出健壯且可讀的實現。數組去重看起來簡單但考察的點是你知不知道多種方式Set一行解決filter indexOf解決但只能處理原始類型Map或對象鍵值處理引用類型。如果面試官追問“[1, 1]去重后有幾個”你就會發現Set用的是SameValueZero比較不會把1和1混掉。防抖和節流是面試必考題也是筆試手寫題常客。防抖debounce的核心是“只認最后一次”短時間內連續觸發只有最后一次等待期結束后才執行。典型場景是搜索框輸入聯想。節流throttle的核心是“限制頻率”不管觸發多少次每段時間最多執行一次。典型場景是滾動事件、resize。實現都不難但要注意this綁定和參數透傳否則改 bug 改到懷疑人生。下面是一個帶this和參數處理的防抖實現function debounce(fn, wait) { let timer null; return function(...args) { const context this; if (timer) clearTimeout(timer); timer setTimeout(() { fn.apply(context, args); }, wait); }; }3. 實操過程與核心環節實現3.1 數組與對象操作常用方法背后的原理筆試題里經常考“下列哪個方法會改變原數組”。很多人用的時候不關心這個但筆試偏偏要考。像push、pop、shift、unshift、splice、sort、reverse會改變原數組而map、filter、reduce、slice、concat不會。如果記不清可以直接用一個技巧方法名暗示是“原地操作”的一般會改。Array.prototype.reduce是高頻考點因為它是“萬能函數式工具”。筆試有時候會讓你用reduce實現map、filter、groupBy或者compose。比如用reduce實現數組扁平化function flatten(arr) { return arr.reduce((acc, cur) { return acc.concat(Array.isArray(cur) ? flatten(cur) : cur); }, []); }對象相關考點則集中在屬性遍歷for...in 與 Object.keys 的區別、對象深比較、可選鏈、解構賦值、展開運算符。有一道經典題是const obj { a: 1 }; const obj2 { ...obj }; obj2.a 2; console.log(obj.a); // 1因為第一層是淺拷貝但如果對象里嵌套了對象展開運算符只能拷貝第一層引用修改嵌套對象會連坐。所以深拷貝必須自己寫遞歸或借助structuredClone或lodash.cloneDeep。筆試寫深拷貝時還要考慮循環引用、日期、RegExp、Map、Set 等情況能寫出一個面試官會點頭的版本能加分不少。3.2 異步流程控制從回調地獄到 Promise異步是前端筆試的“分水嶺”。一部分人看到 Promise 就頭暈但真正理解事件循環后會發現所有異步題都是一個套路同步代碼先執行然后按微任務和宏任務的優先級輪詢執行。你只要記住 Node.js 和瀏覽器的核心差異不是太大最重要的是“每執行完一個宏任務都會清空整個微任務隊列”。下面這個順序題幾乎成為大廠必考console.log(script start); setTimeout(function () { console.log(setTimeout); }, 0); Promise.resolve() .then(function () { console.log(promise1); }) .then(function () { console.log(promise2); }); console.log(script end);輸出依次為script start、script end、promise1、promise2、setTimeout。原因是Promise.then屬于微任務setTimeout屬于宏任務同步代碼結束后會先清空微任務隊列再去取宏任務。如果題目里再加async/await其實也簡單await右邊的表達式會立即執行await之后的代碼相當于.then里的回調會放入微任務隊列。所以看到async題先把同步部分推完再把await后面的內容當作微任務按順序排好即可。3.3 網絡請求與 API 設計前端如何和服務器協作前端筆試還會通過代碼題考察你對HTTP 狀態碼和請求方法語義的理解。比如“創建一個資源用什么方法更新整個資源用什么方法刪除用什么方法”——這就是 RESTful 風格。POST用于創建PUT用于整體更新PATCH用于部分更新DELETE用于刪除。如果對語義不熟接口設計時容易和別人撞車。另外一個高頻點是GET 與 POST 的區別。很多人背“GET 有長度限制、POST 安全”其實不嚴謹。本質區別更多體現在GET 請求通常用于“查詢”參數放到 URL 上會被瀏覽器緩存、會留在歷史記錄里POST 通常用于“提交”參數放 body不會被緩存。至于長度限制其實是服務器或瀏覽器實現的限制不是 HTTP 協議硬性規定。這道題考的是你能不能區分“協議語義”和“實現限制”。還有一類代碼補全題要求你封裝一個request函數處理超時、重試、錯誤碼。實現上核心是“用Promise.race做超時控制”或者“用遞歸/循環做重試”。下面是一個簡化版的超時請求封裝function requestWithTimeout(url, options {}, timeout 5000) { return Promise.race([ fetch(url, options), new Promise((_, reject) { setTimeout(() reject(new Error(timeout)), timeout); }) ]); }這種題看著不難但能把邊界條件想清楚超時后要中斷請求、重試要避免重復提交、loading 狀態如何處理就能體現你寫業務代碼時是否嚴謹。3.4 前端工程化模塊化、構建工具和組件化愛奇藝這套題既然叫前端開發筆試工程化相關的內容也免不了。常見方向有CommonJS 與 ES Module 的區別、Tree Shaking 的原理、webpack 的構建流程、Vue/React 組件通信。CommonJS 和 ES Module 的區別是基礎題但很多人的理解只停留在“一個是require一個是import”。深入一點CommonJS 是同步加載、動態加載、輸出的是值的拷貝ES Module 是靜態分析、異步加載、輸出的是值的引用。這些差異直接決定了瀏覽器和 Node.js 對模塊的處理方式不同。現在 Node.js 同時支持兩種但.mjs與.cjs后綴不同行為也不同筆試有時候會出這個坑。關于組件化前端筆試可能給一段 Vue 或 React 代碼問你父子組件如何通信、跨級組件如何通信、狀態提升是什么。這類題目的核心是“單向數據流”父組件通過 props 向子組件傳數據子組件通過事件回調通知父組件更新。如果項目里狀態復雜再用全局狀態管理Vuex/Redux/Zustand或者 Context/Provide-inject。能把這個邏輯講清楚說明你在團隊協作中不會亂寫全局變量。4. 常見問題與排查技巧實錄4.1 讀代碼題總“想當然”怎么辦讀代碼題是踩坑重災區。最常見的問題就是“還沒理清變量提升就直接按從上到下的順序讀”。比如這段經典代碼var name global; function printName() { console.log(name); var name local; } printName();如果你按順序讀會以為先打印global實際輸出undefined。原因前面說過了函數內var name提升到頂部但賦值不提升。遇到這種“怎么和我想的不一樣”的題先停下來把代碼重寫一遍把所有var聲明提到作用域頂部再模擬執行。還有一個常見問題是忽略嚴格模式。如果代碼開頭有use strict那么this在獨立函數調用中是undefined而不是全局對象。變量賦值時不聲明會直接報錯。很多人在普通模式下測沒問題一旦環境切換就懵。所以做題時先看文件開頭有沒有嚴格模式標記這會改變整個執行結果。4.2 Promise 題老是排錯順序異步順序題出錯通常不是不知道“微任務先執行”而是沒有區分 Promise 構造器中的代碼和.then中的代碼。新手的誤區是以為new Promise里的代碼也是異步的。實際上Promise構造器里的函數是同步執行的只有resolve或reject之后的.then回調才是微任務。舉個例子new Promise((resolve) { console.log(inside); resolve(); console.log(after resolve); }).then(() { console.log(then); });輸出順序是inside、after resolve、then。resolve()只是把狀態改為 fulfilled并不會立即執行.then函數體剩余代碼仍然同步執行完。這個細節在筆試題里經常設陷阱回答的時候不要一看Promise就以為是異步。4.3 布局題老忘記“父容器尺寸不定”的情況CSS 筆試題的另一個高頻失分點是忽略父容器沒有固定高度/寬度時的表現。比如經典的“讓子元素垂直居中”問題很多人直接寫margin: auto但margin: auto只能在水平方向自動居中垂直方向需要display: flex或position transform配合。如果父容器沒有設置高度垂直居中其實沒有意義因為父容器高度由內容撐開。再比如flex: 1的含意很多人只知道“填滿剩余空間”但不清楚它其實是flex-grow: 1; flex-shrink: 1; flex-basis: 0%的簡寫。筆試如果給你一個flex: 1和flex: auto的對比你要能解釋區別flex: 1的 basis 是 0所以不會受內容固有尺寸影響flex: auto的 basis 是auto所以會優先基于內容尺寸分配空間。這一類細節平時寫樣式不注意做題必丟分。4.4 手寫題“會寫但沒考慮邊界”導致扣分手寫代碼題最容易出現“主流程對邊界漏”的情況。比如寫深拷貝只處理了普通對象和數組沒處理null、Date、RegExp、循環引用就會被扣分。實際上面試官看手寫題看的不是你“能不能寫出來”而是你“能不能考慮全面”。我建議你面試前準備一個“模板庫”把高頻手寫題都寫成“帶邊界檢查”的版本而不是網上抄個一行版就背。比如數組去重可以按“原始類型 引用類型 NaN”這三個維度來寫Promise.all要確保“有一個 reject 就整體 reject”還要保證“傳入空數組時返回一個已解決的空數組”。這些邊界條件恰恰是日常寫代碼中最容易忽略的也是區分資深者和初學者的關鍵。5. 深度擴展這份筆試題的深層價值5.1 從筆試看大廠前端的能力模型把愛奇藝筆試題放到更大的視角下看它其實描繪了“大廠前端的能力模型”語言基礎扎實、運行機制清楚、工程化意識強、邊界意識好。這不是愛奇藝一家的要求而是整個行業對成熟前端工程師的通用預期。很多從業三年左右的前端工作里一直在寫業務組件遇到問題就百度、CtrlC/V看起來什么都會但筆試一考就露餡。原因不是不聰明而是沒有建立“原理到實踐”的映射關系。比如用了無數次Array.prototype.map卻答不出它和forEach的本質區別用了無數次display: flex卻不清楚 Flex 容器的三條主軸交叉軸規則。這份筆試題就像一面鏡子能照出你基礎功底的薄弱環節。另外這套題對“學習路徑”也有指導意義。如果你現在還是學生或者剛入行與其追熱點學新框架不如先把 JS 高程、CSS 權威指南、HTTP 權威指南這些“老書”啃透。框架更新換代是常態而語言特性和瀏覽器機制是十年內都不會大變的地基。地基穩了學框架只是換個語法而已。5.2 針對不同階段的備考策略對于在校生和應屆生筆試準備的核心是“刷題 建錯題本”。不要只悶頭在牛客上刷題每次做錯的題都要把“錯誤原因、正確推導、涉及知識點”記下來。過了兩周再拿出來做一遍直到能獨立推導出正確答案為止。針對愛奇藝這套題你可以關注高頻考點但不要跳過你認為“簡單”的部分因為筆試的坑往往就埋在簡單題里。對于已經工作的前端備考重點應該放在“從原理角度重新組織答案”上。比如問你“什么是閉包”不要只回答“函數內部訪問外部變量”而要能畫出作用域鏈、說出內存回收的影響、舉一個實際業務場景比如防抖、柯里化、組件內部函數。這樣你在面試官追問時才能接得住。筆試是筆試面試是面試但能力模型是通的能把面試中講清楚的東西寫到紙面上才說明真的掌握了。5.3 我發現的高頻規律與出題趨勢如果把近年的大廠前端筆試題放在一起看會發現出題趨勢非常明顯越來越重視“真正的場景題”而不再滿足于八股概念。所謂場景題就是“給一個具體業務問題讓你設計實現方案”。比如“有一個搜索框用戶輸入后需要防抖搜索同時要處理競態條件快速輸入時只取最后一次結果你會怎么做”這類題考察的點已經超越了語言語法進入架構設計和邊界思考層面。愛奇藝這套2019年筆試題雖然整體偏基礎但已經能看到這種趨勢的苗頭。比如它會在代碼題里設置“如果某個請求失敗了怎么辦”“如果這里傳的參數是不確定的怎么辦”等鋪陳其實就是在考察邊界處理。現在的筆試題更是直接甩場景實現一個帶并發限制的異步調度器、實現一個 LazyMan、實現一個帶超時的 fetch、實現一個可取消的 Promise。這些題目背后考察的都是抽象能力和工程思維。我個人判斷未來前端筆試的難度還會繼續上探但考點永遠圍繞“語言機制 異步控制 工程化 性能優化”這幾條主線數據結構與算法也在逐漸加重。所以趁早補齊基礎比臨時抱佛腳刷題靠譜太多。5.4 心態調整筆試不是終點而是起點我見過不少候選人因為一套筆試題做崩了就直接放棄這其實挺可惜的。筆試做不好往往不是能力不行而是練習方式不對或者準備周期不夠。你只要把筆試當作一次學習診斷把自己不會的題整理成專題一個個攻破效果遠好于焦慮“我怎么這么菜”。另外提醒一句不要迷信“原題”。網上流傳的題庫再多也不可能押中所有面試題。真正穩妥的做法是把每道題背后的知識點當成一個“知識錨點”從這個錨點延伸出去把相關的概念、原理、應用場景全部復習一遍。比如遇到一道“改變函數 this 指向”的題你可以復習call/apply/bind的區別、手寫bind、箭頭函數、構造函數new的過程、React 類組件中 this 綁定的常見錯誤。這樣一來一道題就變成了一套知識網絡不管怎么變著問你都能應對。