到瀏覽器原理)
先說明一下我是2017年參加的秋招當時考的批次和這份第三批的題目有些重合所以看到這份“百度2018校招Web前端工程師筆試卷第三批”時很多題我都有印象。每年校招季都有人問我要真題、要答案我一般不太建議直接背答案因為百度這幾年的筆試題有個特點——題量不大但每一道題都留了擴展空間面試官真正想看的不是你能不能寫出標準解而是你面對一個開放問題時的思考路徑。這篇文章我不打算把整張卷子的每一道題都復(fù)述一遍畢竟網(wǎng)上隨手能搜到原題我只挑那些有代表性、有深度、值得反復(fù)咀嚼的題目來拆。對于那些正準備投簡歷的同學(xué)與其說這是一份“答案解析”不如說這是幫你少走彎路的“踩坑復(fù)盤”。1. 這份卷子的整體布局從題型看百度的用人標準拿到一張筆試卷先別急著做題先看它考什么、不考什么。這比做對一道題重要得多。1.1 題量不大但覆蓋面很典型2018年這批前端筆試卷總體題型分為幾塊基礎(chǔ)知識選擇題、代碼閱讀題、手寫代碼題、簡答/設(shè)計題。題量大概在二十道左右考試時間我記得是90分鐘。乍一看時間還算充裕但如果手寫代碼題卡住了時間就非常緊張。從知識點分布來看幾個大類的權(quán)重我大概估算一下知識模塊大概占比常見出題形式HTML/CSS20%左右選擇題、閱讀題JavaScript核心35%-40%選擇題、手寫代碼題瀏覽器與網(wǎng)絡(luò)15%左右簡答題、選擇題框架/工程化10%左右簡答題、設(shè)計題邏輯與算法10%-15%手寫代碼題、算法題這個分布說明一個問題百度校招前端筆試JavaScript的比重遠高于HTML/CSS而且考點集中在語言本身的機制上——閉包、作用域、this指向、事件循環(huán)、原型鏈這些幾乎每年必考。1.2 為什么重點考JS而不是框架很多同學(xué)復(fù)習(xí)的時候喜歡死磕Vue或React的源碼結(jié)果筆試一考閉包反而懵了。我在之前帶過的實習(xí)生里見過不少這種情況。這里有個邏輯校招筆試篩的是“底子”不是篩“項目經(jīng)驗”??蚣芨逻@么快今天Vue3、明天React 18如果靠背框架API來篩選那招進來的人可能過兩年就廢了。JS語言機制、瀏覽器原理、網(wǎng)絡(luò)基礎(chǔ)這些十年都不會大變這些才是值得用一整套筆試題去測的東西。我當時復(fù)習(xí)時也犯過類似的錯花了很多時間看框架源碼結(jié)果筆試遇到一道簡單的“用原生JS實現(xiàn)數(shù)組去重”我因為平時都用Set一行搞定反而卡住了。所以這份卷子最大的價值是給你提個醒校招前把原生JS的基本功打牢比什么都重要。2. HTML/CSS部分真題復(fù)盤基礎(chǔ)題也可以挖出深坑這份卷子里的HTML/CSS題表面上看考的都是“基礎(chǔ)”但每一題都有一兩個坑。我挑了三個有代表性的說。2.1 盒模型的計算看似送分實則送命題目大概是給出一個元素的width、padding、border考box-sizing在不同取值下實際渲染寬度是多少。這是前端筆試最經(jīng)典的送分題但拿滿分的人不多。核心考點就兩個box-sizing: content-box默認值下width只包含內(nèi)容區(qū)實際占位寬度 width padding-left padding-right border-left border-right。box-sizing: border-box下width包含了padding和border實際占位寬度就是width。我當時做題時特別留意了題目里有沒有寫box-sizing因為很多題目默認不給這個屬性然后一大堆人默認按border-box算直接就錯了。如果你把這兩條規(guī)則寫清楚再標注“未聲明box-sizing時默認是content-box”閱卷人一眼就看出你基礎(chǔ)扎實。2.2 層疊上下文z-index不是全局的卷子里有一道閱讀題給了幾個嵌套的div設(shè)置了不同的z-index和position問最終哪個元素在最上面。這類題考的是層疊上下文stacking context。常見的坑有這幾個z-index只有在定位元素position不為static且設(shè)置了z-index值時才生效。如果父元素創(chuàng)建了層疊上下文子元素的z-index只在父級上下文內(nèi)部比較不能跨層級和外面的元素比大小。transform、opacity、filter等屬性也會創(chuàng)建層疊上下文即使position是static。我記得這道題給出的元素中有一個設(shè)置了opacity: 0.5很多人會忽略它也能創(chuàng)建層疊上下文結(jié)果排序就錯了。這類題目是真正考“經(jīng)驗”的——沒有實際遇到過層疊上下文問題的人很容易按直覺去比z-index數(shù)值。2.3 兩欄布局的N種寫法手寫代碼題或者簡答題里出現(xiàn)過“左邊固定寬度200px右邊自適應(yīng)”的布局題。這題本身不難但給了你發(fā)揮空間能看出你平時積累的布局方案多不多。我能想到的解決方案有這些float margin-leftposition絕對定位flex布局grid布局table-cell如果是面試我一般會建議至少說出三種并且說明各自的優(yōu)缺點。筆試卷上如果只寫一種雖然也對但沒法展示你的知識廣度。我自己一般先寫flex——代碼最簡潔兼容性對于校招場景來說也夠用然后會補一個float的經(jīng)典方案說明自己了解布局的歷史演進過程。3. JavaScript核心原理題這份卷子的重頭戲JavaScript部分的題目是整張卷子的核心也是拉開分差的地方。我按知識點拆開說。3.1 閉包幾乎所有手寫題都繞不開卷子里有一道題大概是for (var i 0; i 5; i) { setTimeout(function() { console.log(i); }, 1000); }問輸出什么以及如何改成輸出0、1、2、3、4。這道題已經(jīng)老掉牙了但每年都考每次都有很多人掉坑。它考的核心就是var沒有塊級作用域setTimeout里的回調(diào)函數(shù)執(zhí)行時循環(huán)已經(jīng)結(jié)束了i變成了5所以五次輸出都是5。要改成輸出0到4有這幾種方式用let聲名i形成塊級作用域。用IIFE立即執(zhí)行函數(shù)包裹把i作為參數(shù)傳進去。在setTimeout外面套一層函數(shù)利用函數(shù)參數(shù)傳值。我當時選擇用let改寫順便在注釋里補充了IIFE的寫法因為這種題多寫一種方案閱卷人能看出你不只是背了答案真的理解閉包和函數(shù)作用域。有些同學(xué)可能覺得let是ES6語法擔心瀏覽器兼容性但在2018年的筆試環(huán)境下let已經(jīng)被廣泛支持了寫上沒毛病。3.2 this指向和call/apply/bind的區(qū)別卷子里有幾道選擇題和閱讀題考this的指向問題比如普通函數(shù)調(diào)用時this指向什么對象方法調(diào)用時this指向什么箭頭函數(shù)的this和普通函數(shù)有什么區(qū)別如何改變this指向這種題難的不是記憶而是能不能熟練運用。如果問你call、apply、bind三者的區(qū)別標準答案大概是call和apply都是立即執(zhí)行區(qū)別是傳參方式不同call是一個個傳apply是傳數(shù)組。bind不立即執(zhí)行而是返回一個新函數(shù)新函數(shù)的this被永久綁定到指定對象。但真正理解的回答應(yīng)該是這三者都是為了解決function調(diào)用的this丟失問題。實際開發(fā)里最常用的場景是setTimeout里要訪問外部的this或者把對象的方法拆出來單獨調(diào)用時那個方法里的this會變成undefined或window。我還見過筆試題目這樣考手寫一個簡單的bind函數(shù)。思路就是用call或apply像這樣Function.prototype.myBind function(context) { var fn this; var args Array.prototype.slice.call(arguments, 1); return function() { var bindArgs Array.prototype.slice.call(arguments); return fn.apply(context, args.concat(bindArgs)); }; };這類題目考的是你對this和函數(shù)調(diào)用的理解深度不是死記硬背API。3.3 事件循環(huán)Event Loop從輸出順序看異步機制2018年的筆試卷已經(jīng)有了不少關(guān)于事件循環(huán)的題目比如讓判斷一段包含setTimeout、Promise、async/await的代碼的輸出順序。JavaScript的事件循環(huán)機制核心是先執(zhí)行當前宏任務(wù)里的同步代碼執(zhí)行所有微任務(wù)Promise的then回調(diào)、async函數(shù)里的await之后的代碼、MutationObserver回調(diào)等然后執(zhí)行下一個宏任務(wù)setTimeout、setInterval、I/O等數(shù)組里有一個經(jīng)典的題目答案setTimeout(fn, 0)并不是立即執(zhí)行而是要等當前任務(wù)隊列清空后才執(zhí)行。而Promise的resolve會立刻把then回調(diào)放到微任務(wù)隊列所以Promise的輸出可能在setTimeout之前。我見過很多人在這個點翻車因為async函數(shù)對于初學(xué)者來說很容易搞混await之后的代碼什么時候執(zhí)行。我給一個簡單的記憶方法await后面的代碼相當于被放進了then回調(diào)里是微任務(wù)await表達式本身會立刻執(zhí)行如果它是Promise則注冊then回調(diào)如果它是一個普通值也會被包裝成Promise。3.4 數(shù)組去重和排序看似簡單展開很多手寫代碼題里有一道非常經(jīng)典的“數(shù)組去重”。這道題可深可淺一展開全是知識點。最簡單的是ES6的[...new Set(arr)]一行搞定。但如果筆試卷要求不能用Set你就得手寫。我一般會建議按這個思路演進最簡單的雙重循環(huán)逐個比較。優(yōu)化一點用一個hash對象存已出現(xiàn)的值注意類型區(qū)分。再優(yōu)化用indexOf判斷是否已存在。更進一步考慮有序數(shù)組的特殊場景用相鄰比較。性能最優(yōu)Set或Map。如果題目還要求排序那就要注意去重和排序的綜合實現(xiàn)。比如先用filter和indexOf去重再調(diào)用sort排序但如果數(shù)組里有字符串和數(shù)字混合排序結(jié)果可能和預(yù)期不一致因為sort默認按字符串的Unicode編碼排序。我當時寫這道題時特意在代碼注釋里標注了“如果要排序建議先sort再去重”因為對于有序數(shù)組去重可以做到O(n)的時間復(fù)雜度。這種細節(jié)雖然不影響AC但能讓閱卷人看到你思考過邊界問題和復(fù)雜度優(yōu)化。3.5 原型鏈和面向?qū)ο笤嚲砝镞€有一道題考原型鏈我印象很深因為那道題的代碼嵌套了好幾層涉及構(gòu)造函數(shù)、原型、實例之間的指向關(guān)系。核心要記住這幾個點構(gòu)造函數(shù).prototype指向原型對象。實例的__proto__指向構(gòu)造函數(shù)的prototype。所有對象都繼承自O(shè)bject.prototype。函數(shù)也是對象所以函數(shù)也有__proto__。這種題最怕的是把prototype和__proto__搞混。我教別人一個記憶法prototype是構(gòu)造函數(shù)才有的屬性__proto__是每個對象都有的屬性除了用Object.create(null)創(chuàng)建的后者是實例指向原型的橋梁。還有一道題是關(guān)于ES6的class和ES5的構(gòu)造函數(shù)寫法之間的轉(zhuǎn)換這考的是JS面向?qū)ο笤O(shè)計的本質(zhì)。class其實只是語法糖它底層的繼承機制依然是原型鏈。我當時在答題時把class繼承的寫法翻譯成了ES5的原型鏈寫法展示了自己理解class的本質(zhì)。4. 網(wǎng)絡(luò)與瀏覽器簡答題里那些必須答全的知識點前端筆試一般還會考網(wǎng)絡(luò)、瀏覽器相關(guān)的題第三批的卷子里在這塊也出了不少題目。好好復(fù)習(xí)這些知識對校招很有價值。4.1 HTTP狀態(tài)碼不只是記住數(shù)字有一道題考HTTP狀態(tài)碼的含義比如200、301、302、304、401、403、404、500、502、503。很多人能記住幾個常見的但容易混的是301和302還有304。我總結(jié)一個記法301是永久重定向瀏覽器會緩存新的地址以后直接訪問新地址。302是臨時重定向每次還是先訪問舊地址再跳轉(zhuǎn)。304是Not Modified表示資源未修改可以繼續(xù)用本地緩存不需要重新下載。關(guān)于304很多人以為304是“服務(wù)器沒有返回內(nèi)容”其實服務(wù)器返回了狀態(tài)碼304和響應(yīng)頭信息只是沒有響應(yīng)體。這是協(xié)商緩存的機制瀏覽器發(fā)了請求帶If-Modified-Since或If-None-Match頭服務(wù)器判斷內(nèi)容沒變就直接返回304告訴瀏覽器用緩存。4.2 跨域必考的大題跨域幾乎是所有前端筆試卷里必考的百度的這份也不例外。問的方式可能是什么是同源策略如何實現(xiàn)跨域我推薦按這個邏輯答題先解釋為什么要有同源策略為了安全防止惡意網(wǎng)站讀取另一個網(wǎng)站的Cookie或數(shù)據(jù)。指出跨域指的是協(xié)議、域名、端口任一不同。列舉跨域的解決方案JSONP利用script標簽不受同源限制的特點服務(wù)端返回一段JS代碼調(diào)用前端定義好的回調(diào)函數(shù)。CORS后端設(shè)置響應(yīng)頭Access-Control-Allow-Origin。通過postMessage進行跨窗口通信。利用服務(wù)器代理轉(zhuǎn)發(fā)請求。如果筆試只讓你手寫JSONP的實現(xiàn)那核心代碼也不復(fù)雜function jsonp(url, callbackName, success) { var script document.createElement(script); script.src url ?callback callbackName; window[callbackName] function(data) { success(data); document.body.removeChild(script); }; document.body.appendChild(script); }要點是先定義一個全局函數(shù)再動態(tài)插入script標簽服務(wù)端返回的JS會調(diào)用這個全局函數(shù)并傳入數(shù)據(jù)。JSONP只能支持GET請求因為它是通過script標簽加載的這一點一定要提。4.3 瀏覽器緩存機制強緩存和協(xié)商緩存瀏覽器緩存是筆試里另一個高頻考點。核心要能說清楚兩種緩存緩存類型判斷依據(jù)特點強緩存Expires、Cache-Control命中后不發(fā)請求直接用本地緩存協(xié)商緩存Last-Modified/If-Modified-Since、ETag/If-None-Match發(fā)出請求服務(wù)器返回304或200Cache-Control有幾種常見取值no-cache雖然名字叫no-cache但其實每次還是會發(fā)請求驗證一下強緩存是不發(fā)請求直接用的、no-store真正的完全不緩存、max-age緩存多少秒、private/public。在筆試答題時能畫出一個請求和響應(yīng)的時間線來說明這個過程是最直白的答案。我在答題時是畫了一個簡單的表格來描述整個流程因為純文字描述比較繞。5. 開放題和算法題怎么答才有區(qū)分度百度的筆試卷一般還會有一兩道開放性的簡答題和一兩道算法題這部分是拉分的關(guān)鍵。5.1 從一個URL輸入到頁面渲染的過程這是超級經(jīng)典的開放題考的是對整個Web運作流程的理解深度。完整的答案應(yīng)該包含這么幾個階段DNS解析把域名解析成IP地址。TCP連接三次握手建立連接如果是HTTPS還要加上TLS握手。發(fā)送HTTP請求攜帶請求頭、請求體服務(wù)器處理并返回響應(yīng)。瀏覽器收到HTML開始解析。解析HTML生成DOM樹解析CSS生成CSSOM樹。DOM樹和CSSOM樹合并成渲染樹Render Tree。布局Layout計算每個節(jié)點的位置和尺寸。繪制Paint把內(nèi)容畫到屏幕上。這題的深度就藏在每一步的細節(jié)里。比如DNS解析的過程你知不知道有DNS緩存、如何遞歸和迭代查詢TCP三次握手為什么不是兩次CSS是否會阻塞渲染script標簽放在head里會阻塞HTML解析async和defer有什么區(qū)別雖然這一題沒有標準答案但能寫出“渲染樹”和“布局”這種非前端同學(xué)不太知道的詞就能讓閱卷人看出你確實深入學(xué)過瀏覽器原理。5.2 手寫Promise或者async相關(guān)的算法題2018年的筆試卷已經(jīng)開始涉及Promise的手寫實現(xiàn)或者基于Promise的異步流程控制題。我記得有一道題是類似于“限制并發(fā)請求數(shù)量”的題目——給一個URL列表限制最多同時發(fā)起3個請求全部完成后輸出結(jié)果。這道題其實是一道偏向?qū)嶋H工程的算法題。解法思路是維護一個執(zhí)行隊列每次最多執(zhí)行3個任務(wù)一個任務(wù)完成后從隊列里取下一個任務(wù)繼續(xù)執(zhí)行。我當時的思路是寫一個通用的并發(fā)控制函數(shù)function asyncPool(poolLimit, tasks, handler) { const results []; let running 0; let index 0; return new Promise(resolve { function runNext() { if (index tasks.length running 0) { resolve(results); return; } while (running poolLimit index tasks.length) { const current index; running; handler(tasks[current]) .then(res { results[current] res; }) .finally(() { running--; runNext(); }); } } runNext(); }); }這道題考的不只是異步邏輯還考了類似“滑動窗口”的思想保證正在執(zhí)行的請求數(shù)不超過上限同時盡快把任務(wù)隊列跑完。如果你能完全獨立寫出來說明你對Promise的異步流程控制是有真實經(jīng)驗的。5.3 二叉樹相關(guān)的算法題為何會出現(xiàn)在前端筆試卷很多同學(xué)不理解為什么前端筆試還會考二叉樹。其實這不奇怪百度對算法基礎(chǔ)有一定要求尤其是準備做富交互產(chǎn)品的前端團隊會經(jīng)常遇到遞歸遍歷DOM樹、給樹形結(jié)構(gòu)做數(shù)據(jù)轉(zhuǎn)換的場景。我記得第三批的卷子里有一道算法題是“判斷一棵二叉樹是不是對稱的”或者是“二叉樹的最大深度”。這類題的核心解法是遞歸如果你能用非遞歸?;蜿犃械姆绞綄崿F(xiàn)且能分析時間和空間復(fù)雜度那絕對加分。對前端來說二叉樹題等同于樹形結(jié)構(gòu)處理題。比如一個常見的業(yè)務(wù)場景后端返回一個扁平的列表需要轉(zhuǎn)換成樹形結(jié)構(gòu)展示在菜單里。這種題雖然沒直接在筆試里出現(xiàn)但面試時概率極高建議提前背好實現(xiàn)方案。6. 這套題復(fù)盤從題目看2018年前端面試風(fēng)向考完筆試不是終點復(fù)盤才是真正拉開差距的環(huán)節(jié)。我在準備面試時把這份卷子吃透了發(fā)現(xiàn)它和當年前端社區(qū)討論的熱點高度吻合。6.1 手寫代碼題的比重在增加2018年的前端筆試手寫代碼題已經(jīng)占了不少比例不再是一堆選擇題走天下。這說明用人單位希望看到候選人不僅能“知道”還能“寫出來”。手寫題的題型通常集中在數(shù)組相關(guān)操作去重、扁平化、排序?qū)ο笙嚓P(guān)深拷貝、淺拷貝、防抖節(jié)流異步相關(guān)Promise、事件循環(huán)、并發(fā)控制DOM相關(guān)實現(xiàn)事件代理、實現(xiàn)一個簡單的拖拽這些題目的共同點是面試官已經(jīng)默認你有能力獨立寫出這些代碼而不是只會調(diào)用工具庫的API。比如數(shù)組扁平化如果你只會arr.flat()而寫不出遞歸實現(xiàn)那筆試就會吃虧。6.2 CSS布局開始向flex和grid轉(zhuǎn)移2018年的時候flex已經(jīng)非常普及grid也開始在主流瀏覽器里得到支持。筆試卷里已經(jīng)出現(xiàn)和flex布局相關(guān)的題目比如用flex實現(xiàn)水平垂直居中。不過對于校招的筆試我依然建議你掌握浮動布局的經(jīng)典寫法因為實際項目中老代碼可能依然用float而且有些題目會刻意考float的坑比如父元素高度塌陷、清除浮動的幾種方式等。6.3 項目經(jīng)驗的考察變得更“隱蔽”線下筆試一般不會直接問你項目經(jīng)歷但會通過開放題來變相考察你的真實經(jīng)驗。比如“如何設(shè)計一個前端監(jiān)控系統(tǒng)”“如果頁面白屏了你怎么排查”這類問題不是在考你背概念的能力而是在考你有沒有真實處理過線上問題。我在答“頁面白屏怎么排查”的時候?qū)懥俗约旱呐挪樗悸废劝聪翭12看Console有沒有報錯。再看Network里資源有沒有加載接口有沒有返回。再看HTML結(jié)構(gòu)有沒有生成判斷是JS執(zhí)行錯誤還是CSS阻塞。如果是單頁應(yīng)用再查路由配置、動態(tài)import是否有路徑問題。這個思路不是從任何一本書上看來的是我真的被線上白屏問題折磨過之后總結(jié)出來的。這個區(qū)分度閱卷人一眼就能看出來。7. 備考建議如果你現(xiàn)在才開始準備應(yīng)該怎么做很多人問我要2018年的真題其實我更想說的是真題只是載體你通過題復(fù)習(xí)到的知識點才是真正重要的。我先分享一套通用的復(fù)習(xí)框架是我后來帶人時反復(fù)用的。7.1 把知識點歸納成清單逐個過關(guān)我建議把前端知識劃成幾個大塊每一塊定一個過關(guān)標準知識塊過關(guān)標準HTML能默寫常用標簽理解語義化CSS能說清盒模型、層疊上下文、BFC能手寫常見布局JavaScript能默寫閉包、原型鏈、this指向的例子ES6會用let/const、解構(gòu)、箭頭函數(shù)、Promise、async/await瀏覽器原理能從頭到尾講一遍“輸入URL到頁面渲染”的過程網(wǎng)絡(luò)能說清TCP三次握手、HTTP/HTTPS區(qū)別、緩存機制框架至少掌握一個主流框架的核心概念和響應(yīng)式原理光看這個表可能不夠我建議每塊都找真題來練。只背概念而不動手筆試時看到手寫代碼題很容易卡殼。7.2 建立自己的“錯題本”我自己當時在準備面試時用電子筆記建了一個錯題本專門記錄那些“看著會一做就錯”的題。后來復(fù)盤時發(fā)現(xiàn)錯題本的復(fù)習(xí)價值遠大于任何一本參考書。比如我筆記里有一條是關(guān)于事件冒泡和事件委托的。筆試里有時會給一個DOM結(jié)構(gòu)讓你判斷點擊某個元素后事件會經(jīng)過哪些節(jié)點。我一開始老是把冒泡和捕獲搞混于是自己畫了一張事件傳播的示意圖捕獲階段從window到目標元素目標階段在目標元素上冒泡階段再從目標元素回到window。正是這種動手總結(jié)和畫圖的方式讓我的事件機制知識點考得很穩(wěn)。7.3 真題之外的延伸閱讀筆試卷不是孤立存在的。我在做完這份卷子后會順著題目去閱讀相關(guān)的資料比如看MDN上關(guān)于事件循環(huán)的詳細介紹看瀏覽器緩存機制的完整文檔研究Promise的規(guī)范。以Promise為例如果我只是能看懂這句話“Promise是一種異步編程的解決方案”那我遇到手寫Promise.all的題時就會直接懵。但如果我啃過Promise/A規(guī)范知道then方法返回的是一個新Promise就很容易理解Promise鏈式調(diào)用的實現(xiàn)原理。筆試的深度題考的就是你對底層原理理解的厚度。8. 幾個容易被忽略的筆試細節(jié)最后一個部分是經(jīng)驗提醒都是一些容易被忽略、但確實會影響成績的細節(jié)。8.1 看清題目要求和編譯器環(huán)境筆試平臺有的是在線IDE有的只是讓你在文本框里寫代碼。如果是文本框模式多寫注釋很有必要因為你是沒有調(diào)試機會的注釋能幫閱卷人理解你的思路。我在筆試時習(xí)慣在代碼開頭寫一段簡短的解題思路比如// 思路用哈希表記錄每個元素出現(xiàn)的索引遇到重復(fù)時計算距離 // 時間復(fù)雜度O(n)空間復(fù)雜度O(n)這樣既能讓閱卷人快速看出你是有邏輯的也不會因為追求代碼簡潔而讓人看不懂。8.2 注意審題特別是“至少”和“盡可能”很多筆試題會有陷阱比如“至少說出三種方案”“手寫盡可能完整的實現(xiàn)”如果你只寫一種即使完全正確也可能拿不到高分。一個典型的例子是手寫深拷貝。如果你只寫了最簡單的JSON.parse(JSON.stringify(obj))雖然也算一種方案但一旦題目要求“請實現(xiàn)一個較為完整的深拷貝”你至少得考慮循環(huán)引用的處理。正則、Date、Map、Set等特殊對象的處理。Symbol和函數(shù)屬性是否要拷貝。所以筆試題不要急著寫先把題目讀一遍把要求的關(guān)鍵詞圈出來。如果題目說“盡可能完整”就盡量展示你的知識邊界哪怕代碼長一點也沒關(guān)系。8.3 卷面整潔合理分配時間在線筆試不涉及手寫字跡但代碼的排版、命名、注釋是有“觀感”的。一個變量命名清晰、換行規(guī)范的解答和一個把所有代碼壓在一行的解答即使邏輯一模一樣分數(shù)也可能不同。時間分配上我的經(jīng)驗是先做會的題把不會的題留到最后。但前提是你要預(yù)估每道題的分值不要在一道選擇題上浪費10分鐘。遇到開放題寫一半也比空白要好盡量把自己知道的相關(guān)知識點都寫上踩不到分也能讓閱卷人看到你的思路。我在考第三批這套卷子時最后一道算法題寫了一半另一題直接沒寫完但還是進入了面試。后來復(fù)盤時發(fā)現(xiàn)可能是我在前面簡答題里寫了比較完整的思路彌補了后面沒寫完的缺憾。這里也提醒大家不要因為一題沒答好就心態(tài)崩潰筆試里大部分人的分數(shù)都不是滿分的關(guān)鍵是盡量把會做的題都答完整。說到最后我個人的體會是筆試卷是死的但準備過程中的每一次查漏補缺都是活的。2018年的卷子放到今天來看雖然有些題目考察的知識框架和當前前端生態(tài)有一些差異但核心的JS功底、瀏覽器原理、網(wǎng)絡(luò)基礎(chǔ)這幾塊幾乎沒有過時。如果你現(xiàn)在正在準備前端校招遇到這類老題不用覺得過時把它們當成基本功的照妖鏡就好。做錯的題、卡殼的點才是這套題送給你的真正禮物。