前端面试大纲-高频

📅 2026/7/12 22:12:08
前端面试大纲-高频
JS数据类型全解析基本与引用基本数据类型String、Number、Boolean、undefined、null、SymbolES6引用数据类型Object、Array、Function、Date基本数据类型存储在栈中栈用于存储基本数据类型和执行代码引用数据类型存储在堆中块元素、行内元素、行内块元素的区别块元素块元素主要用于页面布局p、h1--h6、center。特点一独占一行默认情况下排列顺序是从上到下。特点二宽度默认是父元素宽度的100%。行内元素主要用来包裹文字span、a。特点一不会独占一行默认情况下是从左到右的顺序排列一行排满后再起一行从左到右的顺序排列。特点二行内元素不可以自定义宽度。行内块元素兼具块元素和行内元素的特点img。特点不会独占一行可以自定义宽度和高度。字符串/数组方法字符串方法concat():方法用于连接两个或多个字符串。该方法没有改变原有字符串但是会返回连接两个或多个新字符串。indexOf()方法可返回某个指定的字符串在字符串中首次出现的位置。如果没有找到匹配的字符串则返回-1.includes()方法用于判断字符串是否包含指定的子字符串。repeat():方法 字符串复制指定次数。replace()方法用于在字符串中用一些字符替换另一些字符或替换一个与正则表达式匹配的子串。split():方法用于吧一个字符串分割成字符串数组。substring()方法用于提取字符串中介于两个指定下标之间的字符。toLowerCase()和toUpperCase()方法把字符串转换为小写/大写。trim()方法用于删除字符串的头尾空白符。数组方法改变原数组的数组方法push():末尾添加数据pop():末尾处删除数据unshift()头部添加数据shift():头部删除数据reverse()翻转数据sort()排序splice():截取数组不改变原数组的数组方法concat()合并数组的返回一个新的数组。join()数组转字符串。返回一个转好的字符串。slice()截取数组的一部分数据。返回截取到的新的数组。indexOf():从左检查数组中有没有这个数值。如果有解耦返回第一次出现的索引如果没有返回-1.lastIndexOf()从右检查数组中有没有这个数值。ES6新增的数组方法forEach():用来循环遍历数组的代替了for。没有返回值 如果真的说要有返回值就是undefinedmap()映射数组的。要returnfilter()用来过滤数组的返回值有就是过滤出来的数据保存在一个数组中。没有的话就返回一个空数组。 要returnevery()判断数组是不是满足所有条件返回true/false。 要returnsome()数组中有没有满足条件的。返回true/false。要returnfind()用来查找数组中满足条件的第一个数据。有就返回没有就是undefined。要returncookie、localStorage、sessionStoragecookie只能保存字符串类型以文本的方式。单个cookie保存的数据不能超过4kb。sessionStorage会话存储。仅在当前浏览器窗口包含新标签页关闭前关闭前有效自然也就不可能持久保持不在不同的浏览器窗口中共享即使是同一个页面localStorage始终有效窗口或浏览器关闭也一直保存因此用作持久数据‘在所有同源窗口中都是共享的new set() 、new map()new set()-----一般都是用来数组去重new map()-----类似于对象属于键值对集合但是此对象的键值有所不同此键值可以包含string/number/object/array或undefined等$nextTick在下次DOM更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法获取更新之后的DOM。nextTick对应的是mounted()生命周期。生命周期中先执行完子组件再执行父组件最后才是App.vue获取token流程为了鉴权。(接口要鉴权)(配置守卫 只有登录有token才进入首页)当用户输入用户名和密码点击登录后, 将用户名和密码发送请求给了后端 后端接收后验证用户信息 验证成功后生成token发送给前端 前端将token保存到本地存储 之后的每次请求都将携带token发送给后端 后端验证token是否有效 有效则返回对应数据 前端展示数据 无效则返回错误信息到登录界面重新登录项目从0--1的过程产品给出需求文档产品原型。评审需求(产品逻辑、交互是否合理)UI出图设计稿1产品给出需求文档产品原型。2阅读文档梳理需求。3评审需求(产品逻辑、交互是否合理)4UI出图设计稿5开会做详细设计(拆分模块、技术选型、技术方案的不确定性什么技术什么框架)6详细设计评审(可不可行)7项目排期(每个阶段预估出时间)8进入开发9搭建项目框架10mock数据(mock.js模拟数据)11实现页面12自测联调13过冒烟case (就是测试基本功能点是否实现达到预期效果。 通常由开发人员自己完成。)14提交测试代码部署测试环境测试人员接入测试15部署上线promisePromise其实是一个构造函数是异步编程的一种解决方案。它有resolverejectthencatch,all,finally,race等静态方法;它的原型prototype上有thencatch方法因此只要作为Promise的实例都可以共享并调用Promise.prototype上面的方法(then,catch) 解决回调地狱 三种状态pending进行中、fulfilled已成功和rejected已失败两种结果从pending变为fulfilled和从pending变为rejectedpromise主要是为了解决js中多个异步回调难以维护和控制的问题.特点1.对象的状态不受外界影响。2.一旦状态改变就不会再改变任何时候都可以得到这个结果。路由跳转有哪些方式 如何实现1.router-link to2.this.$router.push()3.this.$router.replice()4.this.$router.go()5.this.$router.back()闭包能够访问其它函数内部变量的函数就是闭包函数。函数内部再嵌套一个函数并且返回这个函数闭包的好处有1.缓存2.面向对象中的对象3.实现封装防止变量跑到外层作用域中发生命名冲突4.匿名自执行函数匿名自执行函数可以减小内存消耗闭包的坏处1.内存消耗通常来说函数的活动对象会随着执行期上下文一起销毁但是由于闭包引用另外一个函数的活动对象因此这个活动对象无法被销毁这意味着闭包比一般的函数需要更多的内存消耗。尤其在IE浏览器中需要关注。由于IE使用非原生javascript对象实现DOM对象因此闭包会导致内存泄露问题2.性能问题使用闭包时会涉及到跨作用域访问每次访问都会导致性能损失。因此在脚本中最好小心使用闭包它同时会涉及到内存和速度问题。不过我们可以通过把跨作用域变量存储在局部变量中然后直接访问局部变量来减轻对执行速度的影响。优可以访问外层函数的局部变量减少全局变量的声明避免全局污染缺外层函数的变量会长期存储在内存中不会被回收会导致内存泄漏怎么解决内存泄漏被泄露的变量不会被自动回收 手动设置为null;垃圾回收机制内存回收 标记清除 引用计数模块 common.js和es6 模块1、CommonJS是运行时候加载ES6模块是编译的时候输出接口 2、CommonJS是require()同步加载模块ES6模块是import命令是异步加载有一个独立的模块依赖的解析阶段 3、CommonJS模块输出是一个值的拷贝ES6模块输出的值是引用为什么组件化开发复用 管理维护组件中数据是相互独立的不能直接相互引用单页面应用 spa: single page;整个项目只有一个页面页面的切换实际切换不是html页面 切换的是组件传统的项目有多个html页面优势方便管理维护特点不足面试问单页面应用的底层原理是ajaxajax(spa) 有什么不足不利于seo优化首屏加载速度慢影响用户体验 解决办法:懒加载按需引入组件的懒加载 ,代码的压缩合并打包减少http请求速度提不起来骨架屏loading图精灵图雪碧图forEach与map的区别?共同点1只能遍历数组2都是循环遍历数组中的每一项3每一次执行匿名函数都支持三个参数数组中的当前项item当前项的索引index原始数组input4匿名函数中的this都是指windowforEach:这个方式是没有返回值的只是遍历数组中的每一项不对原来数组进行修改但是可以自己通过数组的索引来修改原来的数组map:有返回值可以return出来返回新数据原数组不变。区别map的回调函数中支持return返回值return的是啥相当于把数组中的这一项变为啥并不影响原来的数组只是相当于把原数组克隆了一份把克隆这一份的数组中的对应项改变了 put post 请求区别PUT请求如果两个请求相同后一个请求会把第一个请求覆盖掉。所以PUT用来改资源Post请求后一个请求不会把第一个请求覆盖掉。所以Post用来增资源例:10次PUT 的创建请求与1次PUT 的创建请求相同只会创建一个资源其实后面9次的请求只是对已创建资源的更新且更新内容与原内容相同所以不会产生变化。POST 的重复操作截然不同10次POST请求将会创建10个资源。什么是 event loop事件循环event loop就是 任务在主线程不断进栈出栈的一个循环过程。任务会在将要执行时进入主线程在执行完毕后会退出主线程。 下面就是这个循环的步骤 1.把同步任务队列 或者 微任务队列 或者 宏任务队列中的任务放入主线程。 2.同步任务 或者 微任务 或者 宏任务在执行完毕后会全部退出主线程。vue路由 hash 模式和 history 模式实现原理分别是什么他们的区别是什么hash 模式#后面 hash 值的变化不会导致浏览器向服务器发出请求浏览器不发出请求就不会刷新页面通过监听 hashchange 事件可以知道 hash 发生了哪些变化然后根据 hash 变化来实现更新页面部分内容的操作。history 模式history 模式的实现主要是 HTML5 标准发布的两个 APIpushState 和 replaceState这两个 API 可以在改变 url但是不会发送请求。这样就可以监听 url 变化来实现更新页面部分内容的操作区别url 展示上hash 模式有“#”history 模式没有刷新页面时hash 模式可以正常加载到 hash 值对应的页面而 history 没有处理的话会返回 404一般需要后端将所有页面都配置重定向到首页路由兼容性hash 可以支持低版本浏览器和 IE。script脚本很大出现白屏js阻塞什么是阻塞在页面中我们通常会引用外部文件而浏览器在解析HTML页面是从上到下依次解析、渲染如果head中引用了一个a.js文件而这个文件很大或者有问题需要2秒加载那么浏览器会停止渲染页面此时是白屏显示就是页面啥都没有2秒后加载完成才会继续渲染这个就是阻塞。为什么会阻塞因为浏览器不知道a.js中执行了哪些脚本会对页面造成什么影响所以浏览器会等js文件下载并执行完成后才继续渲染如果这个时间过长会白屏。解决方法;1、推迟加载---如果页面首屏渲染并不依赖js或css,可以推迟加载就是最后再加载js和css把引用外部文件的代码写在最后。2、异步加载---就是告诉浏览器不必等到加载完外部文件可以边渲染边下载什么时候下载完成什么时候执行。最好用在引用外部文件中使用用了async不要使用document.write()方法;使用async时最好不要请求样式信息因为样式表可能尚未加载浏览器会禁止该脚本等待样式表加载完成相当于样式表阻塞脚本执行。为什么使用key?1、key指向一个唯一标识高效的更新虚拟dom2、key主要用来做dom diff算法用的3.没有key的时候默认使用的是“就地复用”策略。如果数据项的顺序被改变Vue不是移动Dom元素来匹配数据项的改变而是简单复用原来位置的每个元素。如果删除第一个元素在进行比较时发现标签一样值不一样时就会复用之前的位置将新值直接放到该位置以此类推最后多出一个就会把最后一个删除掉。webpack?webpack 是前端的一个项目构建/打包工具它是基于 Node.js 开发出来的一个前端工具 打包、转换、优化entry:入口起点入口起点(entry point)指示 webpack 应该使用哪个模块来作为构建其内部依赖图的开始。进入入口起点后webpack 会找出有哪些模块和库是入口起点直接和间接依赖的。outputOutput用于配置打包输出的文件包括输出文件的文件名、输出路径、静态资源地址loaderloader 让 webpack 能够去处理那些非 JavaScript 文件webpack 自身只理解 JavaScript。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块然后你就可以利用 webpack 的打包能力对它们进行处理。mode为什么要用webpack现在的前端项目讲究工程化 模块化 项目的需要越来越复杂网页加载速度慢 因为 我们要发起很多的二次请求要处理错综复杂的依赖关系处理兼容性问题压缩 合并 打包处理css预处理语言 vuets等浏览器不能直接读取的文件如何做前端性能优化减少http请求 雪碧图合并、压缩、精灵图、图片的Base64编码可以使用之前学过的requireJS、也可以使用webpack可以解决各个包之间的复杂依赖关系loader?css-loaderless-loaderbabel-loadervue-loader打包完成后会生成 dist 文件夹如果已经修改了文件路径可以直接打开本地文件查看。 项目上线时只需要将 dist 文件夹放到服务器就行了。把dist文件放入www或root文件就好了。打包后出现页面空白的解决办法首先如果想要打包后直接打开index.html页面查看效果就只需要修改vue.config.js文件找不到这个文件怎么办呢去项目的根目录自己新建一个vue.config.js文件与package.json同级。创建后输入以下代码或:现在需要回到项目中继续在*index.js*中的 *mode:history*前添加一行代码 *base:/dist*module.exports { publicPath:./ }什么是跨域当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域。同源url由协议域名端口和路径组成 如果两个页面的三者都相同就是同源否则就是跨域解决跨域的策略:1 cors大致思路服务器在响应给浏览器数据时会在响应体中携带一些特殊的响应头以告知浏览器可以无视跨域问题。CORS 是一个 W3C 标准全称是跨域资源共享Cross-origin resource sharing。由后端配置 允许跨域2 jsonp大致思路利用script标签的src属性不受同源跨域问题影响的特性但是需要前后端同时进行修改而且只能处理get请求不能处理post请求。JSONP 是服务器与客户端跨源通信的常用方法。 网页通过添加一个script元素向服务器请求 JSON 数据服务器收到请求后将数据放在一个指定名字的回调函数的参数位置传回来3 proxy 代理开发环境 在根目录创建一个 vue.config.js文件夹在里面进行一些配置。暴露模块 devserve里配置 target (目标跨域的url) proxy pathRewrite重写changOrigin:true 允许跨域4 nginx 反向代理生产环境 下载nginx插件创建文件夹找到nginx文件夹下的config.js文件 配置里边的server里的location/api的配置项然后把打包好的dist文件放进来。代理服务器的实现原理因为服务器与服务器之间不受同源策略的影响创建一个同源的虚拟服务器去访问不同源的资源负载均衡增加服务器的数量然后将请求分发到各个服务器上将原先请求集中到单个服务器上的情况改为将请求分发到多个服务器上将负载分发到不同的服务器也就是我们所说的负载均衡。路由传参形式params 传参 特点1. 地址栏不显示参数2. 与 name 搭配进行传参3. 刷新页面数据会丢失query 传参 特点1. 参数显示在地址栏2. 与path搭配进行传参3. 页面刷新数据不丢失http 与https有什么区别http是超文本传输协议信息是明文传输是无状态的端口80.https则是具有安全性的ssl/tls加密传输协议端口443比http更安全。无状态每次的请求都是独立的它的执行情况和结果与前面的请求和之后的请求是无直接关系的它不会受前面的请求应答情况直接影响也不会直接影响后面的请求应答情况”Vue响应系统其核心有三点observe、watcher、depobserve:遍历data中的属性使用 Object.defineProperty 的get/set方法对其进行数据劫持dep每个属性拥有自己的消息订阅器dep用于存放所有订阅了该属性的观察者对象watcher观察者对象通过dep实现对响应属性的监听监听到结果后主动触发自己的回调进行响应ref/reactiveVue 3 引入了 ref 和 reactive 两个核心 API 来管理响应式数据ref用于创建基本类型如字符串、数字的响应式数据返回一个包含 value 属性的对象。reactive用于创建复杂对象或数组的响应式数据返回一个代理对象。使用 ref 时需要通过 .value 访问或修改数据。reactive 只能用于对象或数组不能用于基本类型。var/let/const的区别1.var声明变量时可以重复声明变量后声明的同名变量会覆盖之前声明的遍历。const和let不允许重复声明变量。var声明的变量同名只会打印最后一次声明的值let 和 const同一个作用域下不能重名2.浏览器的全局对象是window。var声明的变量为全局变量并且会将该变量添加为全局对象的属性但是let和const不会。3.什么是变量提升变量能在声明之前使用就是变量提升。var存在变量提升let和const不存在变量提升4.let和const具有块级作用域var不存在块级作用域,可以跨块访问, 不能跨函数访问.var出来的变量是全局的但是不能跨函数访问。5.在使用let、const命令声明变量之前该变量都是不可用的。这在语法上称为暂时性死区。使用var声明的变量不存在暂时性死区。6.在变量声明时var 和 let 可以不用设置初始值。而const声明变量必须设置初始值。const实际上保证的并不是变量的值不得改动而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据数值、字符串、布尔值值就保存在变量指向的那个内存地址因此等同于常量。但对于复合类型的数据主要是对象和数组变量指向的内存地址保存的只是一个指向实际数据的指针const只能保证这个指针是固定的即总是指向另一个固定的地址至于它指向的数据结构是不是可变的就完全不能控制了。引用数据类型的变量存储在 ‘栈内存’ 中值存储在 ‘堆内存’ 中通过指针来指向 ‘堆内存’ 中对应的 值所以const定义的 引用数据类型不可被改变的是 ‘指针’ 所以可以通过 属性来修改值。vue2跟vue3的区别1.vue2.x和vue3.x之间最大的区别。Vue2使用选项类型APIOptions API相比之下Vue3使用合成型APIComposition API。2.vue2 的双向数据绑定是利用ES5 的一个 API Object.definePropert()对数据进行劫持 结合 发布订阅模式的方式来实现的。vue3 中使用了 es6 的 ProxyAPI 对数据代理。3.Vue2 - 这里把数据放入data属性中。在Vue3.0我们就需要使用一个新的setup()方法此方法在组件初始化构造的时候触发。4.生命周期的不同5.vue2只允许一个根节点vue3可以有多个根节点。6.vue2 diff算法就是进行虚拟节点对比并返回一个patch对象用来存储两个节点不同的地方最后用patch记录的消息去局部更新Dom。 vue2 diff算法会比较每一个vnode,而对于一些不参与更新的元素进行比较是有点消耗性能的。vue3 diff算法在初始化的时候会给每个虚拟节点添加一个patchFlagspatchFlags就是优化的标识。 只会比较patchFlags发生变化的vnode,进行更新视图对于没有变化的元素做静态标记在渲染的时候直接复用。7.vue2直接在template中声明refxxx在script中直接this.$refs.xxx就可以了。vue3中8.ref和reactivevite的优势Webpack启动时全量打包所有文件项目越大等待越久Vite基于浏览器原生 ES Module启动不打包只启动服务文件按需请求。Webpack修改文件要重新打包相关模块项目大时刷新卡顿Vite HMR 只更新修改的单个文件和模块数量无关上千组件也能瞬间刷新。Vue/React/Svelte 框架专属优化修改模板、样式不用整页重载保留页面状态。vite原生支持 TS、JSX、Vue、CSS 预处理器scss/less/stylus无需额外配置 loader内置环境变量、路径别名、静态资源处理新建项目几乎零配置就能跑。Webpack 需要手动配 babel-loader、vue-loader、ts-loader、style-loader 一堆规则同步任务 vs 异步任务同步任务代码从上到下排队执行上一行代码没执行完下一行永远等待阻塞主线程。 简单理解一件事做完再做下一件。console.log(1) // 循环阻塞后面代码必须等循环跑完才能执行 for(let i0; i100000000; i){} console.log(2) console.log(3) // 输出顺序1 → 2 → 3异步任务不会阻塞主线程遇到异步代码先放到任务队列主线程同步代码全部执行完再回头执行异步。 简单理解先记下来主线程闲了再处理。console.log(1) setTimeout((){ console.log(3) }, 0) console.log(2) // 输出顺序1 → 2 → 3async /await 和同步、异步关系async/await只是Promise的语法糖本质还是异步只是写法看起来像同步。await会暂停当前函数内部代码让出主线程去执行外部同步代码等待 Promise 完成后恢复函数内部执行。async function fn() { console.log(async内1) // 这里暂停fn内部主线程去执行外面同步代码 await Promise.resolve() console.log(async内2) } console.log(外部同步) fn() console.log(外部同步2)JS 堆 (Heap) 和 栈 (Stack) 完整讲解1. 栈 Stack调用栈 / 栈内存存放基本数据类型引用类型的地址指针 函数执行上下文特点自动分配、自动释放后进先出 LIFO空间小读取极快生命周期函数执行完栈内数据自动销毁无需手动管理2. 堆 Heap堆内存存放引用类型数据Object、Array、Function、RegExp 等真实本体特点空间大、存储结构无序不会自动释放靠垃圾回收 GC 清理栈里只存它的内存地址通过地址去堆里找真实数据基本类型 → 完全存在栈Number / String / Boolean / Null / Undefined / Symbol / BigInt let a 10 let b a b 20 console.log(a) // 10引用类型 → 栈存地址堆存真实数据Object / Array / Function let obj1 { name: 小明 } let obj2 obj1 obj2.name 小红 console.log(obj1.name) // 小红贴上个对比图路由懒加载减小首屏 JS 体积、减少首屏请求、降低 DOM 渲染压力提升页面加载速度默认静态导入所有页面全部打包进index.xxxx.js主包首页加载巨大 懒加载用()import()做代码分割访问路由时才下载对应页面 chunk。import { createRouter, createWebHistory } from vue-router // ❌ 静态导入全部打包进首屏不推荐 // import Home from /views/Home.vue // ✅ 路由懒加载分包 const Home () import(/views/Home.vue) const SchedulePlan () import(/views/schedule/SchedulePlan.vue) const User () import(/views/user/User.vue) const routes [ { path: /, redirect: /schedule }, { path: /schedule, component: SchedulePlan }, { path: /user, component: User } ] const router createRouter({ history: createWebHistory(), routes }) export default router场景如何判断一个数组是空数组1.最通用、推荐arr.length 0数组长度为 0 就是空数组const arr: any[] [] if (arr.length 0) { console.log(是空数组) }2.先判断是不是数组再判断长度防止变量不是数组时报错。用isArrayfunction isEmptyArr(target: unknown): boolean { return Array.isArray(target) target.length 0 } console.log(isEmptyArr([])) // true console.log(isEmptyArr([1,2])) // false console.log(isEmptyArr(null)) // false console.log(isEmptyArr()) // false3.Array.keys()const arr [] const empty arr.keys().next().done // true—————————————版权声明本文为CSDN博主「work_fei」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。原文链接https://blog.csdn.net/work_fei/article/details/125418050有疑问可留言如果帮助到你了记得给个赞哦O(∩_∩)O哈哈,后续会不断更新完善的~~。~~