
2018年秋招那會兒我正好在準備前端方向的校招字節跳動的筆試印象特別深。第二批次的題和第一批不太一樣但考察的核心思路是一致的不看你背了多少API而是看你對JS這門語言的理解深度、對瀏覽器運行機制的認識程度以及工程化實踐里踩過多少坑?,F在回過頭來看這套題很多考點依然是面試高頻區甚至可以說當年這些題目劃定了一個前端工程師基本功的考察范圍。這篇文章把第二批次涉及的核心問題、解題思路和面試延伸展開聊聊給正在準備大廠前端面試的同學做個參考。1. 當年那場筆試整體結構與考察風向1.1 2018年前端技術棧的“時代背景”為什么這決定了題目風格2018年是前端工程化大爆發但又沒完全塵埃落定的一年。Vue 2.x已經非常流行React 16也有了Fiber架構TypeScript開始進入主流視野但還沒完全統治Webpack 4剛發布不久HTTP/2在國內大廠逐步落地但還沒全面普及。當時的前端校招筆試題不會像現在讓你直接寫TS類型體操也不會考你微前端怎么設計因為那時候連微前端這個概念都還沒在工程里普遍應用。那會考察的重心很明確ES6核心語法promise、箭頭函數、解構、class、模塊化、瀏覽器事件循環機制、HTTP緩存策略、閉包與作用域鏈、原型鏈與繼承這些基礎中的基礎。這套題之所以到現在還有參考價值是因為它構建了一個“基礎能力”的考察坐標系——不管框架怎么變、工具鏈怎么演進JS語言本身的特性、瀏覽器的工作機制、網絡協議的基本原理一直是前端工程師能不能走遠的分水嶺?;仡^看第二批次這套題整體題型大致分兩類一類是選擇題覆蓋語法細節、輸出順序、作用域陷阱這類題特別考驗對語言特性的精確掌握另一類是編程題要求手寫實現一些常見功能。選擇題的坑挖得很細不是那種一眼能看出答案的題而是需要你在腦子里把代碼執行過程完整走一遍才能答對。1.2 題型分布與考察模塊占比從總體來看第二批次題目的考察模塊分布大概可以歸納為下表考察模塊典型題型大概占比JS語言核心閉包、this、原型鏈、作用域選擇題、代碼輸出題30%異步編程事件循環、Promise、setTimeout選擇題、代碼輸出題25%瀏覽器與網絡緩存、渲染機制、跨域選擇題、簡答題20%框架與工程化Vue/React基礎、Webpack選擇題15%手寫編程題防抖、深拷貝、數組去重、事件總線編程題10%這個分布很有意思。語言核心和異步編程加在一起超過了一半說明字節當年的思路就是先把語言功底篩出來再談別的??蚣芎凸こ袒恼急确炊桓咭驗樾U猩肼毢髸泻荛L的學習期框架可以現學但JS基礎和異步編程的理解深度一旦欠缺后面補起來非常吃力。這個考察邏輯放到現在的面試里依然是大廠的主流思路。2. 筆試重點題型拆解每一道題背后的考點是什么2.1 JS語言核心類題目閉包、this、原型鏈的經典陷阱第二批筆試的JS語言核心類題目出題風格非常典型——給一段代碼讓你判斷輸出結果或選擇描述正確的選項。這類題表面上看是考語法實際上考的是“你對JavaScript執行機制的理解”。舉個例子閉包類題目經常會這樣出for (var i 0; i 5; i) { setTimeout(function() { console.log(i); }, 100); }答案是輸出5個5。如果你不理解var沒有塊級作用域、以及閉包捕獲的是變量引用而不是值這道題就會答錯。而如果你知道改成let聲明或者用IIFE立即執行函數包一層就能正確輸出0到4并說出背后的原理這道題才算真正吃透。this指向問題同樣是一個高發區。經典的考察方式是var obj { name: byte, getName: function() { return this.name; } }; var fn obj.getName; console.log(fn());這里的坑在于當你把obj.getName賦值給一個變量再調用時函數內部的this就不再指向obj了而是指向全局對象。究其原因this的指向取決于函數調用方式而不是定義位置。這種題在面試中還會以多種變體出現比如嵌套對象里的方法調用、箭頭函數和普通函數的this對比。再說原型鏈的考察。2018年那會很愛考下面這類題function Person(name) { this.name name; } Person.prototype.sayHello function() { console.log(Hello, this.name); }; var p new Person(ByteDancer); p.sayHello(); console.log(p instanceof Person); console.log(p.constructor Person);這道題表面很簡單但面試官往往會在筆試之后的面談環節繼續追問new操作符到底做了什么事如果我把Person.prototype.sayHello改成箭頭函數會怎樣這其實已經把考察從“知不知道”拉到了“能不能說清楚底層機制”的層面。建議你在準備時一定要能把new的過程用代碼描述出來——創建一個新對象、把新對象的__proto__指向構造函數的prototype、將構造函數的this綁定到新對象上、如果構造函數沒有顯式返回對象則返回這個新對象——這四步缺一不可。2.2 異步編程類題目事件循環與Promise的“輸出題”套路異步編程是第二批筆試的重頭戲也是很多同學失分最嚴重的地方。考的不是你能不能寫出Promise而是給你一段混合了setTimeout、Promise、async/await的代碼讓你判斷輸出順序。這類題的底層邏輯基于JavaScript的事件循環機制同步代碼先執行然后是微任務隊列最后是宏任務隊列。但2018年的考題里有幾個容易踩坑的細節第一Promise.resolve().then(...)注冊的回調屬于微任務會在當前宏任務結束后立即執行而setTimeout注冊的回調屬于宏任務要等到下一輪事件循環。所以“先微任務后宏任務”這個規則能幫你快速排除錯誤答案。第二async/await本質上是Promise的語法糖await后面的代碼會作為微任務繼續執行。如果要判斷輸出順序可以先把async函數轉換成Promise鏈的寫法轉換對了輸出順序基本就對了。舉個例子這類題的經典形態是這樣的async function async1() { console.log(async1 start); await async2(); console.log(async1 end); } async function async2() { console.log(async2); } console.log(script start); setTimeout(function() { console.log(setTimeout); }, 0); async1(); new Promise(function(resolve) { console.log(promise1); resolve(); }).then(function() { console.log(promise2); }); console.log(script end);正確答案是script start - async1 start - async2 - promise1 - script end - async1 end - promise2 - setTimeout。如果你能一次答對說明對事件循環的層級關系已經掌握得比較扎實。如果答錯了建議把整個流程手動畫一遍不要用畫圖工具就用紙筆一步一步記錄。為什么因為手畫的過程能逼著你把“當前執行的是哪個任務任務執行完之后隊列里還有什么”這個狀態理清楚。這個能力不僅應對筆試有用排線上問題的時候同樣重要。2.3 瀏覽器與網絡類題目緩存、跨域與渲染機制瀏覽器相關的題目在第二批次里占比不低最常見的兩個方向是HTTP緩存和跨域。HTTP緩存這部分考察的核心是強緩存和協商緩存的區別。選擇題經常這么出如果服務端返回的響應頭里包含Cache-Control: max-age3600瀏覽器在接下來的一個小時內再次請求該資源會怎樣答案是直接從本地緩存讀取不再發起網絡請求。但如果響應頭同時帶有ETag緩存過期后瀏覽器會帶上If-None-Match頭字段去服務端做驗證服務端返回304時瀏覽器繼續使用本地緩存這屬于協商緩存。你要真的吃透緩存體系不能只記字段還要理解瀏覽器為什么設計兩套緩存機制。強緩存的價值是免請求適合長期不變的靜態資源比如打包后的JS文件名帶hash內容變了文件名就變天然適合強緩存。協商緩存的每一次驗證還需要一次網絡請求適合無法確定多長時間內不變的資源。這兩種機制組合起來才能既保證更新及時又最大化利用緩存。跨域問題也是高頻考點。2018年那會兒的核心解法是JSONP和CORS現在的話還會考到代理轉發、postMessage等方式但原理是相通的瀏覽器的同源策略限制的是頁面腳本從一個源去請求另一個源的資源CORS本質上是通過服務端返回Access-Control-Allow-Origin響應頭來告知瀏覽器允許跨域。理解這個原理之后后面的配置就水到渠成。2.4 手寫編程題那些“簡單但容易出錯”的實現編程題方面第二批次的題目大多圍繞數組和函數展開。常見的有數組去重、防抖節流、深拷貝、數組扁平化、事件總線。這些題看起來簡單但真要寫得無懈可擊還是有很多細節需要考慮。以深拷貝為例如果你只寫一個遞歸遍歷對象屬性的版本在筆試中能拿到一些分但距離滿分還有差距。一個完備的深拷貝實現需要處理循環引用用一個WeakMap緩存已拷貝的對象、數組類型、Date和RegExp等特殊對象、Symbol屬性。如果還想做得更完善可以處理函數的拷貝策略通常直接復用引用以及通過原型鏈繼承的屬性。在當前的前端面試中這道題的優化空間依然很大值得花時間把不同版本都寫一遍。防抖和節流也是高頻手寫題。防抖的意思是事件觸發后等待一段時間再執行如果在這段時間內再次觸發則重新等待節流是限制一段時間內最多執行一次。這兩個工具函數的使用場景完全不同——搜索框建議是防抖因為用戶輸入完才去請求滾動加載建議是節流因為不想每個滾動幀都去執行計算。寫實現的時候要特別注意this綁定和參數的透傳因為實際項目里防抖節流往往用在事件處理函數上this指向不能丟。3. 面試延伸從筆試題目到深挖原理的層層追問3.1 手寫Promise與實現一個簡單的Vue響應式系統筆試過了之后面試環節的深挖幾乎必然會從筆試題延伸出來。字節面試官非常擅長從一個簡單的考點發散到一連串相關問題你答到了哪個層面他就順著那個層面繼續往下問。拿Promise來說筆試可能只讓你判斷輸出順序但面試可能直接讓你手寫一個符合Promise/A規范的Promise。手寫Promise是個很好的分水嶺——它能檢驗你對狀態機、回調隊列、then鏈式調用、錯誤處理這些核心機制的理解。我當時寫的時候花了不少時間處理then的回調注冊順序和狀態已經改變后的執行邏輯寫完之后對Promise的執行時序有了豁然開朗的感覺。Vue響應式系統的實現也是一個經典深挖點。2018年在字節面試中出現頻率很高畢竟字節當時內部也大量使用Vue。面試官往往從“Vue 2.x的響應式原理是什么”開始讓你講Object.defineProperty如何攔截屬性讀取和賦值然后追問數組的響應式為什么需要單獨處理再延伸到為什么Vue 3要改用Proxy。這一連串追問的底層邏輯其實是考察你有沒有真正理解“依賴收集”和“觸發更新”這八個字。你會不會實現不重要重要的是能不能用自己的語言把這個過程講清楚。3.2 Webpack構建流程與Loader、Plugin的區別工程化方面第二批次筆試中出現過Webpack相關的基礎選擇題比如loader和plugin的區別、常用的loader有哪些。這類題到了面試環節會變成更開放的問題給你一個場景讓你說說Webpack從入口文件開始經歷了哪些階段最終產出bundle。如果你理解Webpack的整體流程這道題其實可以分幾個層次回答先解析配置找到入口文件然后從入口出發遞歸解析模塊依賴構建依賴圖在解析過程中遇到不同類型的文件交給對應的loader處理比如.vue文件交給vue-loader.css文件交給css-loader和style-loader然后經過插件系統在特定生命周期鉤子中做優化和資源處理最后輸出bundle。Loader和Plugin的區別也在這個流程中體現得很清楚loader負責轉換文件內容Plugin負責在構建流程的特定節點做更復雜的操作。這里有一個很容易被忽視的細節loader的執行順序是從右到左的。如果你寫use: [style-loader, css-loader]Webpack會先執行css-loader把CSS文件解析成JS模塊再執行style-loader把樣式注入到頁面。方向搞反了構建出來的頁面樣式就會出現問題。這類工程化的實操經驗光背書是不行的得自己搭個項目跑一遍構建過程才能有深刻記憶。3.3 項目深挖面試官真正想從你的項目里看到什么字節的面試還有一個顯著特征非常看重項目經驗的真實性。面試官會對你簡歷上寫的項目做“地毯式”追問從技術選型到遇到的具體問題再到解決方案的思考過程每個環節都會細問。這背后的邏輯其實很簡單項目經歷能反映出一個人的技術判斷力和解決復雜問題的能力。如果你在項目里做過性能優化他會問你怎么定位性能瓶頸、怎么量化優化的收益如果你做過前端工程化工具他會問你為什么選Webpack而不選Rollup、遇到構建速度慢的問題是怎么處理的如果你做過組件庫他會問你怎么設計API才能兼顧靈活性和易用性。這類追問最忌諱的就是背答案。最有效的應對方式是在面試前把你做的項目從“整體架構”到“關鍵實現細節”完整梳理一遍尤其要想清楚你做的每個技術決策是出于什么考慮有沒有考慮過其他方案最終為什么選了當前這個如果你能回答出這些“為什么”項目深挖這一關基本就穩了。4. 備戰復盤我踩過的坑和改進后的準備節奏4.1 時間規劃與刷題策略現在回頭看我當時準備校招時犯過兩個比較大的錯誤。第一個是前期過于追求刷題數量而忽略了總結同樣的題型換了個數字重新出現我還是會錯說明沒有從題目中提煉出共性的解題方法。第二個是筆試前沒有限時模擬導致真到了筆試的時候時間分配出現問題——前面的選擇題花的時間過多后面的編程題來不及寫完整。改進之后的節奏可以這樣安排提前三個月開始第一階段以系統復習為主把JS高級程序設計紅寶書里的原型鏈、閉包、異步、DOM、事件等章節過一遍配合MDN文檔補充細節第二階段轉向刷題以??途W的前端題庫和力扣的JavaScript相關題目為主每天固定時間刷一定數量的選擇題和編程題重點記錄錯題第三階段進入模擬沖刺嚴格按照筆試時間來刷整卷并練習手寫代碼的速度和準確性。有一個習慣我覺得特別值得推薦每做錯一道題不要急著看答案先把題目復制下來在旁邊寫清楚“我當時為什么這么想”和“正確答案的邏輯是什么”。等復習后期再翻這些錯題記錄你會發現自己的思維漏洞非常集中往往就是那么幾個點反復出錯這比盲目刷新題要高效得多。4.2 高頻失分點與避坑建議從第二批次和其他大廠筆試題來看有幾個失分點相當集中值得單獨拎出來提示一下。第一個是變量提升和暫時性死區。var聲明的變量會被提升到作用域頂部初始值為undefined而let和const聲明的變量也存在提升但在聲明之前訪問會進入暫時性死區直接報錯。很多同學知道“let不會變量提升”這個結論但不知道為什么遇到具體代碼時容易混淆。這個知識點在筆試選擇題中出現的頻率很高建議把提升和暫時性死區這兩個概念徹底搞清楚包括它們在函數作用域和塊級作用域下的不同表現。第二個是數組方法是否改變原數組。map、filter、reduce不會改變原數組splice、push、pop、sort、reverse會改變原數組。聽起來很簡單但一旦和引用類型的淺拷貝混在一起錯誤率就會飆升。比如對一個二維數組執行slice()得到的“新數組”里層元素仍然是原數組里對象的引用修改里層對象會影響到原數組。這種細節在筆試中經常被用來出陷阱題。第三個是CSS的層疊上下文與BFC。雖然第二批次筆試中CSS占比不高但面試環節很容易被問出來。兩列布局怎么實現、position的幾種值有什么區別、float脫離文檔流之后父元素高度塌陷怎么解決這些經典問題至今仍是面試題庫的???。4.3 學習路線的取舍廣度優先還是深度優先準備校招那段時間我一直在糾結一個問題是先把Vue、React這些框架的文檔都過一遍還是集中精力把JS基礎打牢。當時的實際經驗告訴我對大廠校招來說深度優先是更正確的策略。原因很簡單校招面試官默認你是一個可塑性很強但經驗尚淺的候選人他考察的重心不是你會用多少框架API而是你有沒有能力在未來的工作中快速學習和成長。JS基礎、事件循環、瀏覽器原理、網絡協議這些底層知識是衡量你“學習能力”最可靠的參考指標??蚣軐用娴闹R只要基礎扎實上手新框架往往只需要一兩周。反過來如果基礎不牢就算背了一堆框架API面試官通過幾個深挖問題就能看出你的底子。所以我的建議是把70%的精力花在JS核心、瀏覽器和網絡上剩下30%分給框架和工程化。5. 這套題放到現在還有參考價值嗎5.1 歷久彌新的核心考點客觀來說2018年的這套筆試題放到2026年的今天其中一大部分考點依然是前端面試的必考內容。JS的執行機制、事件循環、閉包、原型鏈、HTTP緩存、跨域、深拷貝和防抖節流的手寫實現這些題目在今天的大廠面試中依然高頻出現。為什么這些考點能一直保持生命力因為它們觸及的是一個前端工程師賴以生存的“底層能力圈”。不管前端框架怎么迭代最終都要運行在JavaScript引擎和瀏覽器提供的運行時環境里不管工具鏈怎么演進網絡請求和資源加載的基本規則沒有本質變化。這部分知識更新速度慢但價值密度高屬于“一年不學不會過期學一次收益多年”的類型。5.2 已經發生變化的考察方向當然前端面試的考察方向也在變化2018年和2026年有一些明顯的差異?,F在的面試更注重TypeScript的類型設計與泛型推導這在2018年基本不是校招考察重點。微前端架構、性能監控體系、前端工程化平臺的建設在新題庫中的出現頻率明顯提升。AI輔助編程工具的出現也讓面試官更關注候選人如何高效使用工具同時考察你是否具備在AI輔助下獨立判斷代碼質量的能力。但這并不意味著2018年的題就過時了。它更像是一面鏡子照出了前端面試“變與不變”的部分。把不變的部分掌握扎實再跟進變化的部分準備校招的路線就清晰很多。5.3 從一套筆試看面試官的選人邏輯最后說說我從這套題里讀出的選人邏輯。字節這類大廠校招面試官真正想選的人不是“背了最多題解的人”而是“能在未知問題面前展示出清晰思考過程的人”。面試官問你一個不會的問題他想看的不是“你承認不會”而是你會怎么去推測、怎么去拆解、怎么去逼近問題的核心。這個能力很難通過短期刷題獲得需要在平時學習新知識時有意識地訓練。有個小方法可以分享平時讀技術文章或源碼的時候不要只記結論試著多問自己幾個“為什么這樣設計”“如果不這樣設計會怎樣”“有沒有其他實現方案”。這種思維習慣一旦養成面試時被問到沒準備過的問題你也能現場推導出一個合理的思路。這一點才是2018年這套題真正想篩選出來的東西。