版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
前端技术模拟面试题及答案Q1:如何理解JavaScript的原型链?原型链的终点是什么?A1:原型链是JavaScript实现继承的核心机制。每个对象(除null外)都有一个内部属性[[Prototype]](可通过__proto__访问),指向其原型对象。当访问对象的属性或方法时,若对象自身不存在该属性,JS引擎会沿着[[Prototype]]链向上查找,直到找到或到达链的末端。原型链的终点是Ototype的[[Prototype]],其值为null。例如,当创建一个普通对象obj={},obj的[[Prototype]]指向Ototype;Ototype的[[Prototype]]是null,因此原型链终止于此。这种设计确保了属性查找的最终边界,避免无限循环。需要注意,通过Object.create(null)创建的对象没有原型链(其[[Prototype]]直接为null),这类对象常被用作纯粹的数据字典,避免与Object原型上的方法(如hasOwnProperty)冲突。Q2:闭包的本质是什么?实际开发中闭包有哪些典型应用场景?A2:闭包的本质是函数在定义时捕获并保留其词法作用域的能力。即使函数在其定义的作用域之外执行,仍能访问原作用域中的变量。这一特性由JS的词法作用域(静态作用域)和函数作为一等公民的特性共同实现。典型应用场景包括:1.模块模式:通过闭包封装私有变量,暴露公共接口。例如:```javascriptconstmodule=(function(){letprivateVar=0;return{increment(){privateVar++},get(){returnprivateVar}};})();module.increment();//privateVar被闭包保留,外部无法直接修改```2.事件处理函数:在循环中绑定事件时,通过闭包保存当前循环变量的状态。例如:```javascriptfor(vari=0;i<5;i++){document.getElementById(`btn${i}`).addEventListener('click',(function(idx){return()=>console.log(idx);//闭包捕获当前idx值})(i));}```3.柯里化(Currying):通过闭包分步接收参数,延迟函数执行。例如:```javascriptconstadd=(a)=>(b)=>a+b;constadd5=add(5);add5(3);//8(闭包保留了a=5)```4.缓存/记忆化(Memoization):利用闭包保存已计算结果,避免重复计算。例如:```javascriptconstmemoize=(fn)=>{constcache={};return(...args)=>{constkey=JSON.stringify(args);returncache[key]??(cache[key]=fn(...args));};};constexpensiveFn=(n)=>{/耗时计算/};constmemoizedFn=memoize(expensiveFn);//闭包保留cache对象```Q3:请描述浏览器事件循环(EventLoop)的执行机制,区分宏任务(Macrotask)和微任务(Microtask)的执行顺序。A3:事件循环是JS引擎协调异步任务执行的核心机制,主要负责将任务从任务队列中取出并执行。其执行流程大致如下:1.执行调用栈中的同步代码(主线程)。2.同步代码执行完毕后,检查微任务队列(MicrotaskQueue),按顺序执行所有微任务(直到队列为空)。3.微任务执行完毕后,进行一次浏览器重渲染(更新DOM)。4.从宏任务队列(MacrotaskQueue)中取出一个宏任务执行,重复步骤2-4。宏任务和微任务的关键区别在于执行时机:宏任务:包括script(整体代码)、setTimeout/setInterval、I/O操作、UI事件、postMessage、requestAnimationFrame(部分浏览器)等。每个宏任务执行后,会触发一次事件循环的“tick”,即执行完当前宏任务后,必须先处理所有微任务,再处理下一个宏任务。微任务:包括Promise.then/catch/finally、MutationObserver、queueMicrotask()等。微任务在当前宏任务执行完成后、下一个宏任务开始前立即执行,且会一次性清空所有已存在的微任务。示例:```javascriptconsole.log('sync');//同步任务,立即执行setTimeout(()=>{//宏任务console.log('setTimeout');},0);Promise.resolve().then(()=>{//微任务console.log('promise1');queueMicrotask(()=>{//微任务(加入当前微任务队列末尾)console.log('queueMicrotask');});});Promise.resolve().then(()=>{//微任务console.log('promise2');});```执行顺序为:sync→promise1→promise2→queueMicrotask→setTimeoutQ4:Vue的响应式系统是如何实现的?Vue3为何改用Proxy替代Object.defineProperty?A4:Vue的响应式系统核心是依赖收集(DependencyTracking)和更新触发(UpdateTriggering)。Vue2中,通过Object.defineProperty为对象的每个属性添加getter和setter:getter:当属性被访问时,将当前活跃的副作用函数(如组件渲染函数)记录到该属性的依赖集合(Dep)中。setter:当属性被修改时,遍历依赖集合,触发所有副作用函数重新执行,更新视图。但Object.defineProperty存在以下限制:1.无法检测对象属性的新增或删除(需手动调用Vue.set/delete)。2.无法监听数组的大部分操作(Vue2通过重写数组原型方法如push/pop来拦截修改)。3.深度响应需要递归遍历对象属性,初始化性能开销较大(尤其对于深层嵌套对象)。Vue3改用Proxy实现响应式,主要优势:1.代理整个对象而非单个属性,可拦截更多操作(如属性访问、赋值、删除、has、ownKeys等),支持检测属性新增/删除(通过deleteProperty和set陷阱)。2.数组操作无需重写原型方法(如push会触发set陷阱,因为修改了数组长度或索引)。3.惰性递归:仅在访问嵌套属性时才会为其创建响应式代理(Vue2需初始化时递归),提升初始化性能。Proxy的核心实现逻辑(简化版):```javascriptconsthandler={get(target,key,receiver){track(target,key);//收集依赖(将当前副作用函数与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);//触发依赖更新}returnresult;}};functionreactive(target){returnnewProxy(target,handler);}```Q5:React的useState钩子中,为什么多次调用setState可能不会立即更新状态?如何确保获取最新的状态?A5:React的状态更新是异步的,这一设计主要为了优化性能(批量更新多个状态变更,减少重新渲染次数)。当调用setState时,React会将状态变更放入更新队列,待当前事件处理完成后(如点击事件回调结束),批量处理所有更新并重新渲染组件。因此,在同一个事件循环中多次调用setState,React可能合并这些更新(尤其当新状态依赖于旧状态时)。例如:```javascriptconst[count,setCount]=useState(0);consthandleClick=()=>{setCount(count+1);//基于旧count(0)setCount(count+1);//仍基于旧count(0)};//最终count变为1(两次更新合并,只执行最后一次)```若需确保获取最新状态,有两种方式:1.使用函数式更新:将setState的参数改为函数,该函数接收最新的状态作为参数。React保证函数式更新会按顺序执行,基于最新的状态计算新值。```javascripthandleClick=()=>{setCount(prev=>prev+1);//基于prev=0→1setCount(prev=>prev+1);//基于prev=1→2};//最终count变为2```2.使用useRef保存最新状态:useRef创建的ref对象在组件生命周期内保持不变,其current属性的变更不会触发重新渲染,但可以同步获取最新值。```javascriptconstcountRef=useRef(count);useEffect(()=>{countRef.current=count;//状态更新后同步到ref},[count]);consthandleClick=()=>{console.log(countRef.current);//总是获取最新值setCount(countRef.current+1);};```Q6:前端性能优化中,如何理解“关键渲染路径(CriticalRenderingPath)”?可以通过哪些指标和手段优化?A6:关键渲染路径指浏览器从接收HTML到渲染出可见内容的整个流程,核心是将HTML、CSS、JS转换为像素的过程。优化关键渲染路径的目标是缩短“首次内容绘制(FCP)”和“最大内容绘制(LCP)”的时间。关键步骤包括:1.解析HTML,构建DOM树。2.解析CSS,构建CSSOM树。3.合并DOM和CSSOM,提供渲染树(RenderTree)。4.计算每个节点的布局(Layout,重排)。5.绘制像素(Paint,重绘)。核心性能指标:FCP(FirstContentfulPaint):首次绘制文本、图片等内容的时间。LCP(LargestContentfulPaint):最大内容元素绘制的时间(通常是图片或大文本块)。TTI(TimetoInteractive):页面可交互的时间(JS执行完成,事件处理就绪)。CLS(CumulativeLayoutShift):累积布局偏移(意外的元素移动导致的视觉抖动)。优化手段:1.减少关键资源数量和大小:内联关键CSS(Above-the-FoldCSS),延迟加载非关键CSS(使用media属性或preload)。压缩HTML/CSS/JS(使用Terser、CSSNano),图片使用WebP/AVIF格式,开启gzip/brotli压缩。避免阻塞渲染的JS:通过async或defer标记脚本(async无序执行,defer按顺序执行且在DOMContentLoaded前完成)。2.优化渲染树构建:减少CSS选择器复杂度(避免嵌套过深的选择器),使用CSSContainment(contain:content)隔离元素的渲染范围,减少重排影响。避免使用@font-face加载大量自定义字体(或通过font-display:swap控制字体加载时的占位表现)。3.减少重排(Layout)和重绘(Paint):使用transform/opacity代替top/width等触发重排的属性(GPU加速)。批量修改DOM(使用DocumentFragment或隐藏元素后修改,再显示)。使用will-change:transform提示浏览器预分配资源。4.优化LCP和CLS:为图片/视频设置width/height属性和aspect-ratio,避免加载时布局偏移。延迟加载非视口内的内容(使用IntersectionObserver实现懒加载)。避免动态插入大尺寸元素(如广告)到已渲染区域。Q7:Webpack的TreeShaking是什么?其生效的前提条件是什么?实际开发中可能遇到哪些阻碍?A7:TreeShaking(摇树优化)是Webpack等打包工具移除代码中未被使用的部分(死代码)的过程,主要用于减少包体积。其核心原理是通过静态分析(ES模块的导入/导出关系)识别未被引用的导出内容,并在打包时排除这些代码。生效前提:1.使用ES模块(import/export),因为CommonJS(require/module.exports)是动态的,无法静态分析。2.代码需无副作用(SideEffects)。即移除某段代码不会影响其他代码的执行结果(如仅导出函数但未被调用,或导出的变量未被使用)。实际开发中可能遇到的阻碍:1.CommonJS模块:若项目依赖中存在CommonJS格式的包(如部分旧库),TreeShaking无法作用于这些模块。可通过配置resolve.mainFields优先使用ES模块版本(如package.json中的“module”字段)。2.副作用代码:Webpack默认认为所有文件可能有副作用(通过package.json的“sideEffects”字段控制)。若代码包含副作用(如全局变量修改、事件监听、console.log等),即使未被直接引用,也可能被保留。需显式声明无副作用(如"sideEffects":false)或列出有副作用的文件(如"sideEffects":["./src/polyfill.js"])。3.动态导入/条件语句:动态import()或if语句中的模块引用(如if(flag){import('./a.js')})会导致静态分析失败,无法正确识别未使用的代码。4.Babel转译:若Babel将ES模块转译为CommonJS(如@babel/preset-env的modules:'auto'配置),会破坏ES模块的静态结构,导致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函数会被TreeShaking移除```Q8:Vue3的CompositionAPI相比OptionsAPI有哪些优势?在什么场景下更适合使用CompositionAPI?A8:CompositionAPI是Vue3推出的新代码组织方式,通过import导入组合函数(Composables),将逻辑按功能拆分,而非按选项(data、methods、computed等)拆分。相比OptionsAPI,其优势主要体现在:1.逻辑复用更灵活:OptionsAPI通过mixin复用逻辑,但存在命名冲突、数据来源不清晰等问题(多个mixin可能定义同名data或method)。CompositionAPI通过组合函数(如useFetch、useTimer)封装逻辑,返回响应式状态和方法,调用时显式解构,明确数据来源。例如:```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.代码组织更清晰:复杂组件可能包含多个不相关的逻辑(如表单验证、数据请求、用户交互),OptionsAPI会将这些逻辑分散在data、methods、watch等选项中,难以追踪。CompositionAPI按逻辑块组织代码,相关的状态、方法、生命周期钩子集中在一起,提高可维护性。3.更好的类型推导:CompositionAPI通过ref/reactive显式创建响应式对象,结合TypeScript时,类型推导更准确(如ref<string>('')明确类型)。OptionsAPI的data函数返回对象的类型需手动声明,复杂类型容易出错。4.更小的打包体积:CompositionAPI的核心函数(如ref、reactive、onMounted)可通过TreeShaking移除未使用的部分,而OptionsAPI的选项(如methods)无论是否使用都会被打包。适合使用CompositionAPI的场景:复杂组件(包含多个逻辑关注点)。需要复用跨组件逻辑(通过组合函数)。与TypeScript深度集成的项目。追求更细粒度的逻辑控制(如动态依赖收集)。Q9:React的Fiber架构解决了什么问题?其核心设计思想是什么?A9:Fiber架构是React16+引入的核心更新机制,主要解决旧版Reconciler(协调器)在复杂应用中导致的页面卡顿问题。旧版Reconciler使用递归方式进行虚拟DOM对比(StackReconciler),该过程是同步的、不可中断的。当组件树较深时,递归会长期占用主线程,导致浏览器无法及时处理用户输入或动画,出现卡顿(尤其是在16ms的渲染帧期间无法完成更新)。Fiber架构的核心设计思想是“增量更新”(IncrementalUpdates),将原本同步的递归对比拆分为多个小任务(Fiber节点),每个任务可中断、恢复、调整优先级。其关键特性包括:1.任务优先级:为每个更新任务分配优先级(如用户输入触发的更新优先级高于数据请求的更新),高优先级任务可中断低优先级任务,确保用户交互的流畅性。2.可中断的调和过程:Fiber使用“双缓冲”技术(DoubleBuffering),维护当前渲染的树(currenttree)和正在计算的工作树(work-in-progresstree)。当任务被中断时,可从上次中断的位置继续执行,不影响已渲染的内容。3.链表结构替代递归:Fiber节点通过child、sibling、return属性连接成链表(树结构转为链表),使调和过程可以通过循环遍历而非递归,支持任务的暂停和恢复。Fiber的工作流程分为两个阶段:调和阶段(ReconciliationPhase):计算需要更新的Fiber节点,标记副作用(如插入、更新、删除)。此阶段可中断,任务按优先级执行。提交阶段(CommitPhase):将调和阶段的结果应用到真实DOM,此阶段不可中断(需保证DOM更新的原子性)。通过Fiber架构,React能够更好地利用浏览器的空闲时间(通过requestIdleCallback)执行低优先级任务,同时确保高优先级任务(如动画、输入)及时响应,显著提升了复杂应用的性能和用户体验。Q10:如何实现一个线程安全的前端本地存储方案?需要考虑哪些边界条件?A10:本地存储(如localStorage、sessionStorage)是单线程同步的,在多标签页或WebWorker中可能存在竞态条件(RaceConditions)。实现线程安全的存储方案需解决以下问题:1.多标签页数据同步:localStorage的storage事件仅在其他标签页修改数据时触发,当前标签页修改不会触发,需手动同步。2.并发写入冲突:多个标签页同时修改同一键值,可能导致数据覆盖。3.数据一致性:确保读取和写入操作的原子性(如读取后修改再写入的过程不被其他操作打断)。实现方案(以localStorage为例):步骤1:使用“锁”机制控制并发写入。通过设置一个临时锁键(如`lock:${key}`),标记当前有进程在修改数据,其他进程需等待锁释放。步骤2:利用storage事件监听其他标签页的修改,保持数据同步。步骤3:使用版本号或时间戳解决写入冲突(如后写入的版本覆盖旧版本)。示例代码(简化版):```javascriptclassSafeStorage{constructor(){this.lockKeyPrefix='lock:';this.versionKeySuffix=':version';//监听storage事件,同步数据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){//其他标签页写入了更高版本,更新本地数据和版本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. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026四川成都彭州市人民医院第一批招聘48人笔试备考题库及答案解析
- 2025云南省招商中铁控股有限公司校园招聘备考题库及答案详解一套
- 2026上半年云南事业单位联考文山州招聘143人备考考试试题及答案解析
- 2026年市场营销策略消费者行为分析与市场调研题集
- 2026北京保障房中心有限公司法律管理岗招聘1人备考题库及参考答案详解1套
- 2026四川长虹电源股份有限公司招聘总账主管会计岗位1人备考题库含答案详解
- 2026内蒙古鄂尔多斯市合创控股集团有限公司招聘6人备考题库带答案详解
- 2026广东第二师范学院基础教育集团招聘4人备考题库参考答案详解
- 2026年影视化妆专业人士的生物化学基础知识速成题目
- 2026年高级工程师职称评定考试题目
- (完整版)房屋拆除施工方案
- 供水管道抢修知识培训课件
- 广东物业管理办法
- 业务规划方案(3篇)
- 大客户开发与管理课件
- 上海物业消防改造方案
- 供应商信息安全管理制度
- 2025年农业机械化智能化技术在农业防灾减灾中的应用报告
- 发展与安全统筹策略研究
- 移动式压力容器安全技术监察规程(TSG R0005-2011)
- 绿化工程监理例会会议纪要范文
评论
0/150
提交评论