前端技術(shù)模擬面試題及答案_第1頁
前端技術(shù)模擬面試題及答案_第2頁
前端技術(shù)模擬面試題及答案_第3頁
前端技術(shù)模擬面試題及答案_第4頁
前端技術(shù)模擬面試題及答案_第5頁
已閱讀5頁,還剩24頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

前端技術(shù)模擬面試題及答案Q1:如何理解JavaScript的原型鏈?原型鏈的終點是什么?A1:原型鏈?zhǔn)荍avaScript實現(xiàn)繼承的核心機制。每個對象(除null外)都有一個內(nèi)部屬性[[Prototype]](可通過__proto__訪問),指向其原型對象。當(dāng)訪問對象的屬性或方法時,若對象自身不存在該屬性,JS引擎會沿著[[Prototype]]鏈向上查找,直到找到或到達鏈的末端。原型鏈的終點是Ototype的[[Prototype]],其值為null。例如,當(dāng)創(chuàng)建一個普通對象obj={},obj的[[Prototype]]指向Ototype;Ototype的[[Prototype]]是null,因此原型鏈終止于此。這種設(shè)計確保了屬性查找的最終邊界,避免無限循環(huán)。需要注意,通過Object.create(null)創(chuàng)建的對象沒有原型鏈(其[[Prototype]]直接為null),這類對象常被用作純粹的數(shù)據(jù)字典,避免與Object原型上的方法(如hasOwnProperty)沖突。Q2:閉包的本質(zhì)是什么?實際開發(fā)中閉包有哪些典型應(yīng)用場景?A2:閉包的本質(zhì)是函數(shù)在定義時捕獲并保留其詞法作用域的能力。即使函數(shù)在其定義的作用域之外執(zhí)行,仍能訪問原作用域中的變量。這一特性由JS的詞法作用域(靜態(tài)作用域)和函數(shù)作為一等公民的特性共同實現(xiàn)。典型應(yīng)用場景包括:1.模塊模式:通過閉包封裝私有變量,暴露公共接口。例如:```javascriptconstmodule=(function(){letprivateVar=0;return{increment(){privateVar++},get(){returnprivateVar}};})();module.increment();//privateVar被閉包保留,外部無法直接修改```2.事件處理函數(shù):在循環(huán)中綁定事件時,通過閉包保存當(dāng)前循環(huán)變量的狀態(tài)。例如:```javascriptfor(vari=0;i<5;i++){document.getElementById(`btn${i}`).addEventListener('click',(function(idx){return()=>console.log(idx);//閉包捕獲當(dāng)前idx值})(i));}```3.柯里化(Currying):通過閉包分步接收參數(shù),延遲函數(shù)執(zhí)行。例如:```javascriptconstadd=(a)=>(b)=>a+b;constadd5=add(5);add5(3);//8(閉包保留了a=5)```4.緩存/記憶化(Memoization):利用閉包保存已計算結(jié)果,避免重復(fù)計算。例如:```javascriptconstmemoize=(fn)=>{constcache={};return(...args)=>{constkey=JSON.stringify(args);returncache[key]??(cache[key]=fn(...args));};};constexpensiveFn=(n)=>{/耗時計算/};constmemoizedFn=memoize(expensiveFn);//閉包保留cache對象```Q3:請描述瀏覽器事件循環(huán)(EventLoop)的執(zhí)行機制,區(qū)分宏任務(wù)(Macrotask)和微任務(wù)(Microtask)的執(zhí)行順序。A3:事件循環(huán)是JS引擎協(xié)調(diào)異步任務(wù)執(zhí)行的核心機制,主要負(fù)責(zé)將任務(wù)從任務(wù)隊列中取出并執(zhí)行。其執(zhí)行流程大致如下:1.執(zhí)行調(diào)用棧中的同步代碼(主線程)。2.同步代碼執(zhí)行完畢后,檢查微任務(wù)隊列(MicrotaskQueue),按順序執(zhí)行所有微任務(wù)(直到隊列為空)。3.微任務(wù)執(zhí)行完畢后,進行一次瀏覽器重渲染(更新DOM)。4.從宏任務(wù)隊列(MacrotaskQueue)中取出一個宏任務(wù)執(zhí)行,重復(fù)步驟2-4。宏任務(wù)和微任務(wù)的關(guān)鍵區(qū)別在于執(zhí)行時機:宏任務(wù):包括script(整體代碼)、setTimeout/setInterval、I/O操作、UI事件、postMessage、requestAnimationFrame(部分瀏覽器)等。每個宏任務(wù)執(zhí)行后,會觸發(fā)一次事件循環(huán)的“tick”,即執(zhí)行完當(dāng)前宏任務(wù)后,必須先處理所有微任務(wù),再處理下一個宏任務(wù)。微任務(wù):包括Promise.then/catch/finally、MutationObserver、queueMicrotask()等。微任務(wù)在當(dāng)前宏任務(wù)執(zhí)行完成后、下一個宏任務(wù)開始前立即執(zhí)行,且會一次性清空所有已存在的微任務(wù)。示例:```javascriptconsole.log('sync');//同步任務(wù),立即執(zhí)行setTimeout(()=>{//宏任務(wù)console.log('setTimeout');},0);Promise.resolve().then(()=>{//微任務(wù)console.log('promise1');queueMicrotask(()=>{//微任務(wù)(加入當(dāng)前微任務(wù)隊列末尾)console.log('queueMicrotask');});});Promise.resolve().then(()=>{//微任務(wù)console.log('promise2');});```執(zhí)行順序為:sync→promise1→promise2→queueMicrotask→setTimeoutQ4:Vue的響應(yīng)式系統(tǒng)是如何實現(xiàn)的?Vue3為何改用Proxy替代Object.defineProperty?A4:Vue的響應(yīng)式系統(tǒng)核心是依賴收集(DependencyTracking)和更新觸發(fā)(UpdateTriggering)。Vue2中,通過Object.defineProperty為對象的每個屬性添加getter和setter:getter:當(dāng)屬性被訪問時,將當(dāng)前活躍的副作用函數(shù)(如組件渲染函數(shù))記錄到該屬性的依賴集合(Dep)中。setter:當(dāng)屬性被修改時,遍歷依賴集合,觸發(fā)所有副作用函數(shù)重新執(zhí)行,更新視圖。但Object.defineProperty存在以下限制:1.無法檢測對象屬性的新增或刪除(需手動調(diào)用Vue.set/delete)。2.無法監(jiān)聽數(shù)組的大部分操作(Vue2通過重寫數(shù)組原型方法如push/pop來攔截修改)。3.深度響應(yīng)需要遞歸遍歷對象屬性,初始化性能開銷較大(尤其對于深層嵌套對象)。Vue3改用Proxy實現(xiàn)響應(yīng)式,主要優(yōu)勢:1.代理整個對象而非單個屬性,可攔截更多操作(如屬性訪問、賦值、刪除、has、ownKeys等),支持檢測屬性新增/刪除(通過deleteProperty和set陷阱)。2.數(shù)組操作無需重寫原型方法(如push會觸發(fā)set陷阱,因為修改了數(shù)組長度或索引)。3.惰性遞歸:僅在訪問嵌套屬性時才會為其創(chuàng)建響應(yīng)式代理(Vue2需初始化時遞歸),提升初始化性能。Proxy的核心實現(xiàn)邏輯(簡化版):```javascriptconsthandler={get(target,key,receiver){track(target,key);//收集依賴(將當(dāng)前副作用函數(shù)與target[key]綁定)constvalue=Reflect.get(target,key,receiver);if(isObject(value)){//惰性遞歸代理嵌套對象returnreactive(value);}returnvalue;},set(target,key,value,receiver){constoldValue=Reflect.get(target,key,receiver);constresult=Reflect.set(target,key,value,receiver);if(oldValue!==value){trigger(target,key);//觸發(fā)依賴更新}returnresult;}};functionreactive(target){returnnewProxy(target,handler);}```Q5:React的useState鉤子中,為什么多次調(diào)用setState可能不會立即更新狀態(tài)?如何確保獲取最新的狀態(tài)?A5:React的狀態(tài)更新是異步的,這一設(shè)計主要為了優(yōu)化性能(批量更新多個狀態(tài)變更,減少重新渲染次數(shù))。當(dāng)調(diào)用setState時,React會將狀態(tài)變更放入更新隊列,待當(dāng)前事件處理完成后(如點擊事件回調(diào)結(jié)束),批量處理所有更新并重新渲染組件。因此,在同一個事件循環(huán)中多次調(diào)用setState,React可能合并這些更新(尤其當(dāng)新狀態(tài)依賴于舊狀態(tài)時)。例如:```javascriptconst[count,setCount]=useState(0);consthandleClick=()=>{setCount(count+1);//基于舊count(0)setCount(count+1);//仍基于舊count(0)};//最終count變?yōu)?(兩次更新合并,只執(zhí)行最后一次)```若需確保獲取最新狀態(tài),有兩種方式:1.使用函數(shù)式更新:將setState的參數(shù)改為函數(shù),該函數(shù)接收最新的狀態(tài)作為參數(shù)。React保證函數(shù)式更新會按順序執(zhí)行,基于最新的狀態(tài)計算新值。```javascripthandleClick=()=>{setCount(prev=>prev+1);//基于prev=0→1setCount(prev=>prev+1);//基于prev=1→2};//最終count變?yōu)?```2.使用useRef保存最新狀態(tài):useRef創(chuàng)建的ref對象在組件生命周期內(nèi)保持不變,其current屬性的變更不會觸發(fā)重新渲染,但可以同步獲取最新值。```javascriptconstcountRef=useRef(count);useEffect(()=>{countRef.current=count;//狀態(tài)更新后同步到ref},[count]);consthandleClick=()=>{console.log(countRef.current);//總是獲取最新值setCount(countRef.current+1);};```Q6:前端性能優(yōu)化中,如何理解“關(guān)鍵渲染路徑(CriticalRenderingPath)”?可以通過哪些指標(biāo)和手段優(yōu)化?A6:關(guān)鍵渲染路徑指瀏覽器從接收HTML到渲染出可見內(nèi)容的整個流程,核心是將HTML、CSS、JS轉(zhuǎn)換為像素的過程。優(yōu)化關(guān)鍵渲染路徑的目標(biāo)是縮短“首次內(nèi)容繪制(FCP)”和“最大內(nèi)容繪制(LCP)”的時間。關(guān)鍵步驟包括:1.解析HTML,構(gòu)建DOM樹。2.解析CSS,構(gòu)建CSSOM樹。3.合并DOM和CSSOM,提供渲染樹(RenderTree)。4.計算每個節(jié)點的布局(Layout,重排)。5.繪制像素(Paint,重繪)。核心性能指標(biāo):FCP(FirstContentfulPaint):首次繪制文本、圖片等內(nèi)容的時間。LCP(LargestContentfulPaint):最大內(nèi)容元素繪制的時間(通常是圖片或大文本塊)。TTI(TimetoInteractive):頁面可交互的時間(JS執(zhí)行完成,事件處理就緒)。CLS(CumulativeLayoutShift):累積布局偏移(意外的元素移動導(dǎo)致的視覺抖動)。優(yōu)化手段:1.減少關(guān)鍵資源數(shù)量和大小:內(nèi)聯(lián)關(guān)鍵CSS(Above-the-FoldCSS),延遲加載非關(guān)鍵CSS(使用media屬性或preload)。壓縮HTML/CSS/JS(使用Terser、CSSNano),圖片使用WebP/AVIF格式,開啟gzip/brotli壓縮。避免阻塞渲染的JS:通過async或defer標(biāo)記腳本(async無序執(zhí)行,defer按順序執(zhí)行且在DOMContentLoaded前完成)。2.優(yōu)化渲染樹構(gòu)建:減少CSS選擇器復(fù)雜度(避免嵌套過深的選擇器),使用CSSContainment(contain:content)隔離元素的渲染范圍,減少重排影響。避免使用@font-face加載大量自定義字體(或通過font-display:swap控制字體加載時的占位表現(xiàn))。3.減少重排(Layout)和重繪(Paint):使用transform/opacity代替top/width等觸發(fā)重排的屬性(GPU加速)。批量修改DOM(使用DocumentFragment或隱藏元素后修改,再顯示)。使用will-change:transform提示瀏覽器預(yù)分配資源。4.優(yōu)化LCP和CLS:為圖片/視頻設(shè)置width/height屬性和aspect-ratio,避免加載時布局偏移。延遲加載非視口內(nèi)的內(nèi)容(使用IntersectionObserver實現(xiàn)懶加載)。避免動態(tài)插入大尺寸元素(如廣告)到已渲染區(qū)域。Q7:Webpack的TreeShaking是什么?其生效的前提條件是什么?實際開發(fā)中可能遇到哪些阻礙?A7:TreeShaking(搖樹優(yōu)化)是Webpack等打包工具移除代碼中未被使用的部分(死代碼)的過程,主要用于減少包體積。其核心原理是通過靜態(tài)分析(ES模塊的導(dǎo)入/導(dǎo)出關(guān)系)識別未被引用的導(dǎo)出內(nèi)容,并在打包時排除這些代碼。生效前提:1.使用ES模塊(import/export),因為CommonJS(require/module.exports)是動態(tài)的,無法靜態(tài)分析。2.代碼需無副作用(SideEffects)。即移除某段代碼不會影響其他代碼的執(zhí)行結(jié)果(如僅導(dǎo)出函數(shù)但未被調(diào)用,或?qū)С龅淖兞课幢皇褂茫嶋H開發(fā)中可能遇到的阻礙:1.CommonJS模塊:若項目依賴中存在CommonJS格式的包(如部分舊庫),TreeShaking無法作用于這些模塊??赏ㄟ^配置resolve.mainFields優(yōu)先使用ES模塊版本(如package.json中的“module”字段)。2.副作用代碼:Webpack默認(rèn)認(rèn)為所有文件可能有副作用(通過package.json的“sideEffects”字段控制)。若代碼包含副作用(如全局變量修改、事件監(jiān)聽、console.log等),即使未被直接引用,也可能被保留。需顯式聲明無副作用(如"sideEffects":false)或列出有副作用的文件(如"sideEffects":["./src/polyfill.js"])。3.動態(tài)導(dǎo)入/條件語句:動態(tài)import()或if語句中的模塊引用(如if(flag){import('./a.js')})會導(dǎo)致靜態(tài)分析失敗,無法正確識別未使用的代碼。4.Babel轉(zhuǎn)譯:若Babel將ES模塊轉(zhuǎn)譯為CommonJS(如@babel/preset-env的modules:'auto'配置),會破壞ES模塊的靜態(tài)結(jié)構(gòu),導(dǎo)致TreeShaking失效。需配置modules:false保留ES模塊。示例:```javascript//utils.js(ES模塊)exportfunctiona(){console.log('a');}exportfunctionb(){console.log('b');}//app.jsimport{a}from'./utils.js';a();//打包后,utils.js中未被使用的b函數(shù)會被TreeShaking移除```Q8:Vue3的CompositionAPI相比OptionsAPI有哪些優(yōu)勢?在什么場景下更適合使用CompositionAPI?A8:CompositionAPI是Vue3推出的新代碼組織方式,通過import導(dǎo)入組合函數(shù)(Composables),將邏輯按功能拆分,而非按選項(data、methods、computed等)拆分。相比OptionsAPI,其優(yōu)勢主要體現(xiàn)在:1.邏輯復(fù)用更靈活:OptionsAPI通過mixin復(fù)用邏輯,但存在命名沖突、數(shù)據(jù)來源不清晰等問題(多個mixin可能定義同名data或method)。CompositionAPI通過組合函數(shù)(如useFetch、useTimer)封裝邏輯,返回響應(yīng)式狀態(tài)和方法,調(diào)用時顯式解構(gòu),明確數(shù)據(jù)來源。例如:```javascript//useFetch.jsexportfunctionuseFetch(url){constdata=ref(null);consterror=ref(null);constfetchData=async()=>{try{data.value=awaitfetch(url).then(res=>res.json());}catch(err){error.value=err;}};return{data,error,fetchData};}//Component.vueimport{useFetch}from'./useFetch.js';exportdefault{setup(){const{data,error,fetchData}=useFetch('/api/data');onMounted(fetchData);return{data,error};}};```2.代碼組織更清晰:復(fù)雜組件可能包含多個不相關(guān)的邏輯(如表單驗證、數(shù)據(jù)請求、用戶交互),OptionsAPI會將這些邏輯分散在data、methods、watch等選項中,難以追蹤。CompositionAPI按邏輯塊組織代碼,相關(guān)的狀態(tài)、方法、生命周期鉤子集中在一起,提高可維護性。3.更好的類型推導(dǎo):CompositionAPI通過ref/reactive顯式創(chuàng)建響應(yīng)式對象,結(jié)合TypeScript時,類型推導(dǎo)更準(zhǔn)確(如ref<string>('')明確類型)。OptionsAPI的data函數(shù)返回對象的類型需手動聲明,復(fù)雜類型容易出錯。4.更小的打包體積:CompositionAPI的核心函數(shù)(如ref、reactive、onMounted)可通過TreeShaking移除未使用的部分,而OptionsAPI的選項(如methods)無論是否使用都會被打包。適合使用CompositionAPI的場景:復(fù)雜組件(包含多個邏輯關(guān)注點)。需要復(fù)用跨組件邏輯(通過組合函數(shù))。與TypeScript深度集成的項目。追求更細粒度的邏輯控制(如動態(tài)依賴收集)。Q9:React的Fiber架構(gòu)解決了什么問題?其核心設(shè)計思想是什么?A9:Fiber架構(gòu)是React16+引入的核心更新機制,主要解決舊版Reconciler(協(xié)調(diào)器)在復(fù)雜應(yīng)用中導(dǎo)致的頁面卡頓問題。舊版Reconciler使用遞歸方式進行虛擬DOM對比(StackReconciler),該過程是同步的、不可中斷的。當(dāng)組件樹較深時,遞歸會長期占用主線程,導(dǎo)致瀏覽器無法及時處理用戶輸入或動畫,出現(xiàn)卡頓(尤其是在16ms的渲染幀期間無法完成更新)。Fiber架構(gòu)的核心設(shè)計思想是“增量更新”(IncrementalUpdates),將原本同步的遞歸對比拆分為多個小任務(wù)(Fiber節(jié)點),每個任務(wù)可中斷、恢復(fù)、調(diào)整優(yōu)先級。其關(guān)鍵特性包括:1.任務(wù)優(yōu)先級:為每個更新任務(wù)分配優(yōu)先級(如用戶輸入觸發(fā)的更新優(yōu)先級高于數(shù)據(jù)請求的更新),高優(yōu)先級任務(wù)可中斷低優(yōu)先級任務(wù),確保用戶交互的流暢性。2.可中斷的調(diào)和過程:Fiber使用“雙緩沖”技術(shù)(DoubleBuffering),維護當(dāng)前渲染的樹(currenttree)和正在計算的工作樹(work-in-progresstree)。當(dāng)任務(wù)被中斷時,可從上次中斷的位置繼續(xù)執(zhí)行,不影響已渲染的內(nèi)容。3.鏈表結(jié)構(gòu)替代遞歸:Fiber節(jié)點通過child、sibling、return屬性連接成鏈表(樹結(jié)構(gòu)轉(zhuǎn)為鏈表),使調(diào)和過程可以通過循環(huán)遍歷而非遞歸,支持任務(wù)的暫停和恢復(fù)。Fiber的工作流程分為兩個階段:調(diào)和階段(ReconciliationPhase):計算需要更新的Fiber節(jié)點,標(biāo)記副作用(如插入、更新、刪除)。此階段可中斷,任務(wù)按優(yōu)先級執(zhí)行。提交階段(CommitPhase):將調(diào)和階段的結(jié)果應(yīng)用到真實DOM,此階段不可中斷(需保證DOM更新的原子性)。通過Fiber架構(gòu),React能夠更好地利用瀏覽器的空閑時間(通過requestIdleCallback)執(zhí)行低優(yōu)先級任務(wù),同時確保高優(yōu)先級任務(wù)(如動畫、輸入)及時響應(yīng),顯著提升了復(fù)雜應(yīng)用的性能和用戶體驗。Q10:如何實現(xiàn)一個線程安全的前端本地存儲方案?需要考慮哪些邊界條件?A10:本地存儲(如localStorage、sessionStorage)是單線程同步的,在多標(biāo)簽頁或WebWorker中可能存在競態(tài)條件(RaceConditions)。實現(xiàn)線程安全的存儲方案需解決以下問題:1.多標(biāo)簽頁數(shù)據(jù)同步:localStorage的storage事件僅在其他標(biāo)簽頁修改數(shù)據(jù)時觸發(fā),當(dāng)前標(biāo)簽頁修改不會觸發(fā),需手動同步。2.并發(fā)寫入沖突:多個標(biāo)簽頁同時修改同一鍵值,可能導(dǎo)致數(shù)據(jù)覆蓋。3.數(shù)據(jù)一致性:確保讀取和寫入操作的原子性(如讀取后修改再寫入的過程不被其他操作打斷)。實現(xiàn)方案(以localStorage為例):步驟1:使用“鎖”機制控制并發(fā)寫入。通過設(shè)置一個臨時鎖鍵(如`lock:${key}`),標(biāo)記當(dāng)前有進程在修改數(shù)據(jù),其他進程需等待鎖釋放。步驟2:利用storage事件監(jiān)聽其他標(biāo)簽頁的修改,保持?jǐn)?shù)據(jù)同步。步驟3:使用版本號或時間戳解決寫入沖突(如后寫入的版本覆蓋舊版本)。示例代碼(簡化版):```javascriptclassSafeStorage{constructor(){this.lockKeyPrefix='lock:';this.versionKeySuffix=':version';//監(jiān)聽storage事件,同步數(shù)據(jù)window.addEventListener('storage',(e)=>{if(e.key?.startsWith(this.lockKeyPrefix))return;//忽略鎖事件constkey=e.key;constnewVersion=Number(e.newValue?.split('|')[1])||0;constcurrentVersion=Number(localStorage.getItem(`${key}${this.versionKeySuffix}`))||0;if(newVersion>currentVersion){//其他標(biāo)簽頁寫入了更高版本,更新本地數(shù)據(jù)和版本localStorage.setItem(key,e.newValue.split('|')[0]);localStorage.setItem(`${key}${this.versionKeySuffix}`,newVersion);}});}asyncget(key){constvalue=localStorage.getItem(key);constversion=localStorage.getItem(`${key}${this.versionKeySuffix}`);return{value,version:Number(version)||0};}asyncset(key,value,timeout=3000){constlockKey=`${this.lockKeyPrefix}${key}`;conststart=Date.now();

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論