前端面试题大杂烩:事件流、大屏、WebSocket、Vue原理一次讲透!
最近整理了一波前端面试题,发现很多知识点特别碎,但面试官又爱问。今天就干脆把这些高频问题用大白话串一遍,每一小节都尽量说人话,保证你看完能记住个七八成。适合面试前突击,也适合平时查漏补缺。走起!
1. 前端中的事件流
事件流说白了就是浏览器里一个事件从触发到响应的整个传递过程。它分三个阶段:
- 捕获阶段:事件从最外层
window一直往下找,找到触发事件的那个元素。 - 目标阶段:事件到达目标元素,触发它身上绑定的事件。
- 冒泡阶段:事件从目标元素再往上冒,依次触发父级元素的事件。
平时咱们用addEventListener的时候,第三个参数默认是false,也就是在冒泡阶段触发。如果设成true,就是在捕获阶段触发。
事件流最大的用处就是事件委托:把子元素的事件绑到父元素上,通过e.target判断具体是哪个子元素被点了,省内存还方便动态添加元素。
2. 大屏开发常用的组件库有哪些
大屏开发(可视化大屏)常用的库和组件:
- DataV:阿里出品,专门做大屏的 Vue 组件库,边框、装饰、图表都有,开箱即用。
- ECharts:百度出品,图表库天花板,大屏里图表基本靠它。
- AntV:蚂蚁出品,包含 G2、G6、L7 等,适合复杂可视化。
- vue-big-screen/vue-data-visualization:一些开源大屏模板,可以直接改数据用。
- Three.js:做 3D 大屏效果时用。
- 高德/百度地图 API:地图类大屏常用。
实际项目里一般是DataV 做边框装饰 + ECharts 做图表 + 自己写布局。
3. get 请求可以进行请求体传参吗
理论上可以,HTTP 规范没有明确禁止 GET 请求带 body。你用axios或fetch确实可以给 GET 请求塞一个body。
axios.get('/api',{data:{name:'zhangsan'}})但实际开发中不建议,而且很多环境直接给你忽略掉。因为:
- 浏览器对 GET 请求的 body 支持不统一,有的直接丢弃。
- 服务器(如 Tomcat、Nginx)默认不解析 GET 的 body。
- 缓存、代理、日志等中间件通常只处理 GET 的 URL,不管 body。
所以结论:规范没禁止,但工程上别这么干,参数放 URL 上更靠谱。
4. get 为什么接口怎么传 body 参数都穿不过去
接着上面说,主要有几个原因:
- 浏览器限制:
XMLHttpRequest和fetch虽然能发 body,但部分浏览器或版本对 GET + body 支持不完整,发送时直接被忽略。 - 服务器不解析:很多后端框架(如 Spring MVC)默认从 URL 或 query 里取 GET 参数,根本不会读 body,所以你传了也白传。
- 中间层拦截:Nginx、网关、CDN 等对 GET 请求的 body 处理不一致,可能直接丢弃或报错。
所以如果你发现 GET 传 body 怎么都过不去,别挣扎了,换成 POST 或者把参数拼到 URL 上,这是最省心的办法。
5. 前端如何给接口的 response-headers 响应头加参数
先泼盆冷水:真实接口的响应头是后端设置的,前端没法直接改。但有些场景咱们确实想给响应头加点东西,比如调试、本地 mock、跨域加头,可以这么干:
- 本地开发代理:在
vue.config.js的devServer.proxy里用onProxyRes给响应头加参数。
devServer:{proxy:{'/api':{target:'http://localhost:3000',changeOrigin:true,onProxyRes(proxyRes){proxyRes.headers['X-Custom-Header']='hello'}}}}- Service Worker:可以拦截请求并修改响应,但复杂度高。
- 本地 mock:自己写接口时直接设置响应头。
但生产环境前端是没办法改后端响应头的,除非你用 Nginx 等反向代理。
6. 前端可以修改 response-headers 响应头的 set-cookie 参数吗
不能!这是浏览器安全策略死死卡住的。
Set-Cookie是后端通过响应头下发的,浏览器会自动处理成 Cookie,但前端 JavaScript:
- 读不到
Set-Cookie响应头(被浏览器隐藏)。 - 不能修改响应头里的
Set-Cookie。 - 只能通过
document.cookie读取或设置一部分非HttpOnly的 Cookie,但这也只是操作本地 Cookie,不是改响应头。
所以想改Set-Cookie,只能让后端改逻辑,或者走代理(比如本地代理改写响应头),但真实用户访问时前端是无能为力的。
7. 绝对路径与相对路径
- 绝对路径:从根目录开始的完整路径,比如
/home/user/index.html或https://www.baidu.com/logo.png。前端里以/开头的路径也是绝对路径(相对于域名根)。 - 相对路径:相对于当前文件位置的路径,比如
./images/logo.png(当前目录)、../css/style.css(上一级目录)。
前端项目里,绝对路径的好处是不怕文件层级变动,但换域名或部署到子目录时可能要改;相对路径更灵活,但层级深了容易写错。一般建议用绝对路径(以/开头)或配置base。
8. Tomcat 的使用需要依赖后端环境吗
Tomcat 本身是 Java 写的,所以运行它必须要有 Java 环境(JDK/JRE)。这是硬性依赖。
但“后端环境”如果指的是业务后端代码,那倒不一定:
- 你可以把前端打包好的静态文件(HTML、JS、CSS)扔进 Tomcat 的
webapps目录,Tomcat 就变成一个静态资源服务器,这时候不需要任何 Java 业务代码。 - 但如果要跑 JSP、Servlet 或 Spring Boot 之类的后端服务,那就需要完整的 Java 后端环境。
所以结论:Tomcat 依赖 Java 运行环境,但不一定依赖后端业务代码。
9. vue 项目 proxy 代理多个接口地址
在vue.config.js里可以配置多个代理规则,用不同的前缀区分:
module.exports={devServer:{proxy:{'/api':{target:'http://localhost:3000',changeOrigin:true},'/user':{target:'http://localhost:4000',changeOrigin:true},'/upload':{target:'http://localhost:5000',changeOrigin:true,pathRewrite:{'^/upload':''}}}}}这样前端请求/api/xxx就会转发到3000,/user/xxx转发到4000,互不干扰。记得路径重写pathRewrite按需配置。
10. 插件和控件的区别
简单理解:
- 控件(Control):有 UI 界面的组件,比如按钮、输入框、日期选择器,用户能直接看到并操作。
- 插件(Plugin):是对宿主程序功能的扩展,不一定有界面。比如浏览器的广告拦截插件、Vue 的路由插件、webpack 插件等。
一句话:控件偏 UI,插件偏功能扩展。控件可以是插件的一部分,但插件不一定有控件。
11. 插件和软件有什么区别
- 软件:可以独立运行的程序,比如 Photoshop、Chrome、微信。
- 插件:不能独立运行,必须依附在某个宿主软件上,用来增强宿主功能,比如 PS 的滤镜插件、浏览器的油猴插件。
打个比方:软件是房子,插件是房子里装的智能家居,没有房子,智能家居用不了。
12. 前端修改路径参数怎么禁止
这个问题可能想问:怎么防止用户手动修改 URL 上的参数(比如 query 或 params)?
说实话,前端没法完全禁止用户改 URL,因为 URL 就在浏览器地址栏,用户随时能改。但咱们可以做一些校验和限制:
- 路由守卫:在
beforeEach里校验参数合法性,不合法就重定向或重置。
router.beforeEach((to,from,next)=>{if(!/^\d+$/.test(to.query.id)){next({path:to.path,query:{id:'1'}})// 重置为默认值}else{next()}})- 状态管理:把关键参数存在 Vuex/Pinia 里,不依赖 URL 参数,用户改了 URL 也不影响逻辑。
- 加密签名:给参数加签名,后端校验,但前端只能算辅助。
核心思想:前端只能校验和引导,真正的安全要靠后端。
13. WinSCP 原理
WinSCP 是 Windows 下一款文件传输工具,用来和服务器之间传文件。它的原理是基于SSH 协议,具体使用 SFTP 或 SCP 协议:
- SFTP:基于 SSH 的安全文件传输协议,加密传输,支持断点续传。
- SCP:基于 SSH 的简单文件复制协议。
简单说,WinSCP 就是通过 SSH 建立加密连接,然后在这个安全通道里传输文件,所以比传统 FTP 安全得多。前端部署项目时经常用它把打包文件传到服务器。
14. 前端 WebSocket
WebSocket 是一种全双工通信协议,让浏览器和服务器之间可以互相主动发消息,不用像 HTTP 那样一问一答。
前端用法:
constws=newWebSocket('ws://localhost:8080')ws.onopen=()=>{ws.send('你好服务器')}ws.onmessage=(event)=>{console.log('收到消息:',event.data)}ws.onclose=()=>{console.log('连接关闭')}使用场景:实时聊天、在线客服、大屏数据实时刷新、股票行情、多人协作等。注意心跳保活、断线重连。
15. Vue 的 nextTick 原理
nextTick是 Vue 提供的一个方法,用来在下次 DOM 更新完成后执行回调。比如你改了数据,想立刻获取更新后的 DOM,就得用它:
this.message='新值'this.$nextTick(()=>{console.log(this.$refs.box.textContent)// 能拿到最新值})原理:Vue 更新 DOM 是异步的,数据变化后不会立刻更新视图,而是先收集依赖,等同一事件循环里的所有数据变化都完成后,再统一更新 DOM。nextTick就是利用微任务(Promise.then)或宏任务(setTimeout)把回调放到 DOM 更新之后执行。
简单说:数据变了 → 等本轮事件循环结束 → 更新 DOM → 执行 nextTick 回调。
16. 什么是应用服务器
应用服务器(Application Server)是提供业务逻辑运行环境的服务器软件。它不仅能处理静态资源,还能运行业务代码,比如 Java 的 Servlet、EJB、Spring 等。
常见的应用服务器:
- Tomcat(轻量级,支持 Servlet/JSP)
- WebLogic、WebSphere(重型,支持完整 Java EE)
- JBoss/WildFly
和 Web 服务器(如 Nginx、Apache)的区别:Web 服务器主要处理静态资源和反向代理,应用服务器更侧重运行业务逻辑。
17. 路由守卫判断非 vue 页面
在 Vue 路由守卫里,如果要判断用户想跳转的是一个非 Vue 管理的页面(比如外部链接),可以这么处理:
router.beforeEach((to,from,next)=>{// 判断是否是外部链接if(to.path.startsWith('http://')||to.path.startsWith('https://')){window.location.href=to.path// 直接跳走return}// 判断某个路由是否在 Vue 路由表中if(!router.hasRoute(to.name)){next('/404')// 不存在就跳 404}else{next()}})核心思路:在守卫里检查to.path或to.name,如果发现不是 Vue 内部路由,就用window.location跳转或重定向到 404。
18. 前端 SM4 的 ECB 在线解密
SM4 是国产对称加密算法,ECB 是其中一种加密模式(电子密码本模式)。前端解密可以用sm-crypto这个库:
import{sm4}from'sm-crypto'// 密文和密钥一般是十六进制字符串constcipherText='...'// 密文constkey='0123456789abcdeffedcba9876543210'// 128位密钥,32个十六进制字符// ECB 解密constplainText=sm4.decrypt(cipherText,key,{mode:'ecb',cipherType:'text'})console.log(plainText)注意:
- 密钥必须是 128 位(32 个十六进制字符)。
- 密文格式要匹配,
cipherType可以是text或base64。 - ECB 模式不需要 IV 向量。
- 在线解密工具原理一样,就是把密文和密钥输入,调用同样的算法还原明文。
19. 前端中间件是啥
前端中间件就是在数据流中间插入的处理函数,请求进来后先经过它,再继续往下走。它可以在不修改核心逻辑的情况下,扩展功能。
常见的前端中间件:
- Axios 拦截器:请求拦截、响应拦截。
- Redux 中间件:在 action 到达 reducer 之前处理副作用。
- Vue Router 导航守卫:也算一种路由中间件。
- Koa/Express 中间件:后端中间件,但前端全栈时也会接触。
举个例子(Axios 拦截器):
axios.interceptors.request.use(config=>{config.headers.token='xxx'// 统一加 tokenreturnconfig})这就是一个典型的请求中间件。
20. 前端开源框架是啥
前端开源框架就是别人开源出来的、帮咱们快速搭建前端项目的工具集。主流的有:
- Vue:渐进式框架,上手简单,国内生态好。
- React:Facebook 出品,函数式编程,生态庞大。
- Angular:Google 出品,大而全,适合大型企业级应用。
- Svelte:新兴框架,编译时框架,运行时更小。
它们都是开源的,可以免费使用、修改和分发,有庞大的社区支持。
21. 前端三大件的渲染顺序
前端三大件指的是HTML、CSS、JavaScript。浏览器渲染页面的顺序大致是:
- 解析 HTML:生成 DOM 树。
- 解析 CSS:生成 CSSOM 树。
- 合并 DOM 和 CSSOM:生成渲染树(Render Tree)。
- 布局(Layout):计算每个节点的位置和大小。
- 绘制(Paint):把内容画到屏幕上。
JS 会阻塞 DOM 解析,所以一般把<script>放在</body>前,或者用defer/async属性。CSS 会阻塞渲染,所以首屏 CSS 要尽快加载。
渲染顺序简单记:先结构(HTML),再样式(CSS),再交互(JS),但 JS 可能阻塞前面两步。
22. vue-cli 各版本的区别
- Vue CLI 2.x:基于模板(template)生成项目,配置文件暴露在外,如
build/webpack.base.conf.js等,需要手动配置。 - Vue CLI 3.x:全新设计,零配置,隐藏了 webpack 配置,通过
vue.config.js自定义,引入插件体系。 - Vue CLI 4.x:在 3 基础上优化,支持更多默认配置,性能更好,默认使用 Vue 3 相关生态(但也可以选 Vue 2)。
- Vue CLI 5.x:进一步升级,默认 webpack 5,更好的兼容性和构建速度。
现在新项目基本都用Vue CLI 5.x或直接上Vite了。
23. vue-cli3 比 vue-cli2 好在哪
- 零配置:不用再折腾
build和config目录,开箱即用。 - 插件化:通过
vue add安装插件,自动集成,比如vue add router、vue add vuex。 - 图形化界面:
vue ui可以可视化创建和管理项目。 - 现代模式:自动构建出支持旧浏览器的 legacy 包和支持新浏览器的 modern 包。
- 配置统一:都在
vue.config.js里,清晰好维护。 - 更好的默认优化:内置了代码分割、缓存、压缩等。
总之,CLI 3 让开发者从配置地狱里解脱出来,专注于业务。
24. vue.config.js 文件是在 vue-cli 几中出现的
Vue CLI 3.x 开始出现vue.config.js。
在 Vue CLI 2.x 里,配置文件分散在config/index.js和build/目录下。从 3.x 起,所有自定义配置统一放到项目根目录的vue.config.js里,比如代理、打包路径、webpack 配置等。
25. vue-cli3 为什么没有 webpack
这个问题其实是个误解!Vue CLI 3 依然使用 webpack,只是把 webpack 配置隐藏了。
在 Vue CLI 3 里,webpack 的默认配置被封装在@vue/cli-service内部,项目里看不到webpack.config.js。如果你想自定义,就在vue.config.js里通过configureWebpack或chainWebpack修改。
所以不是没有 webpack,而是配置被抽象了,不再直接暴露。
26. js 将一个键值对对象转为可遍历数据
对象本身不是可迭代的,但可以用这几个方法转换:
- Object.entries(obj):返回二维数组
[[key, value], ...],可以直接for...of遍历。 - Object.keys(obj):返回键数组。
- Object.values(obj):返回值数组。
- for…in:遍历键,但会遍历到原型链,要配合
hasOwnProperty。
示例:
constobj={a:1,b:2,c:3}// 最常用for(const[key,value]ofObject.entries(obj)){console.log(key,value)}27. js 把 export 的对象全部导入
如果模块里导出了多个东西,想一次性全部导入,用import * as:
// module.jsexportconsta=1exportconstb=2exportfunctionfn(){}// 导入import*asallfrom'./module.js'console.log(all.a,all.b)all.fn()这样all就是一个包含所有导出的对象。
28. vue-cli3 设置路由懒加载
路由懒加载就是用到哪个页面才加载哪个页面,加快首屏速度。在 Vue CLI 3 里用动态import()语法即可:
constHome=()=>import('./views/Home.vue')constAbout=()=>import('./views/About.vue')constroutes=[{path:'/',component:Home},{path:'/about',component:About}]webpack 会自动把每个动态导入的组件打包成单独的 chunk,路由切换时按需加载。
29. es6 的 class 类使用场景
ES6 的class是语法糖,本质还是基于原型继承。常见使用场景:
- 封装工具类:比如日期处理、字符串处理。
- 创建组件类:React 类组件、Vue 早期组件。
- 面向对象编程:继承、多态,适合复杂的业务模型。
- 单例模式:用
static方法和属性实现。 - 事件管理器:封装事件监听和触发。
示例:
classEventBus{constructor(){this.events={}}on(name,fn){(this.events[name]||=[]).push(fn)}emit(name,data){this.events[name]?.forEach(fn=>fn(data))}}30. 怎样看 vscode 是否成功拉取远程最新代码
在 VSCode 里拉取远程代码(git pull)后,可以通过以下几种方式确认:
- 看输出日志:源代码管理面板会显示拉取结果,如果成功会提示
Already up to date或显示更新的文件。 git log:在终端执行git log -1,看最新提交时间和远程是否一致。git status:如果显示Your branch is up to date with 'origin/main',说明拉取成功。- 对比文件:查看某个已知有更新的文件内容是否变了。
- VSCode 左下角:会显示当前分支和同步状态,如果显示
↓0 ↑0说明没有待拉取或推送的提交。
最直接的就是看git pull的输出有没有报错,没报错且提示更新了,就算成功。
31. 阻止冒泡排序要对父子都使用方法吗
这里应该是阻止事件冒泡,不是冒泡排序哈。
只需要在子元素的事件处理函数里调用e.stopPropagation()即可,不需要父子都加。
原理:事件从子元素冒泡到父元素,如果在子元素阶段就调用了stopPropagation(),事件就不会继续往上冒了,父元素的事件就不会触发。
<div@click="parentClick"><button@click="childClick">点我</button></div>childClick(e){e.stopPropagation()// 阻止冒泡,父元素 parentClick 不会执行}如果父子都调用了stopPropagation(),那只是重复保险,但没必要。只有一种特殊情况:事件委托时,需要在父元素里判断e.target来决定是否阻止。
32. 前端事件循环
前端事件循环(Event Loop)是 JS 处理异步任务的机制。JS 是单线程的,但通过事件循环实现了非阻塞。
主要概念:
- 调用栈:同步代码在这里执行。
- 宏任务(Macro Task):
setTimeout、setInterval、I/O、UI 渲染。 - 微任务(Micro Task):
Promise.then、async/await、MutationObserver。 - 执行顺序:先执行同步代码 → 清空微任务队列 → 执行一个宏任务 → 再清空微任务 → 下一个宏任务……循环往复。
示例:
console.log('1')setTimeout(()=>console.log('2'),0)Promise.resolve().then(()=>console.log('3'))console.log('4')// 输出:1 4 3 2理解事件循环是搞懂nextTick、异步编程的基础。
33. 大屏使用可视化插件注意事项
大屏开发用可视化插件(ECharts、DataV 等)时,有几个坑要留意:
- 分辨率适配:大屏分辨率五花八门,要用缩放方案(如
transform: scale)或百分比布局。 - 性能优化:图表太多、数据量大时,要用防抖节流、按需渲染、销毁不用的图表。
- 内存泄漏:定时刷新数据的定时器、事件监听,组件销毁时一定要清理。
- 字体和颜色:大屏通常深色背景,字体要清晰,颜色对比度要高。
- 数据实时性:WebSocket 或轮询刷新时,注意更新频率,避免频繁重绘。
- 浏览器兼容:大屏机器可能用 Chrome 或专用浏览器,提前测试。
- 打包体积:按需引入 ECharts 模块,减小包体积。
34. es6 数组处理方法
ES6 给数组加了很多好用方法:
map:返回新数组,每个元素经过处理。filter:返回符合条件的元素组成的新数组。reduce:累加器,汇总数组。forEach:遍历,无返回值。find:找到第一个符合条件的元素。findIndex:找到第一个符合条件的索引。some:只要有一个满足就返回true。every:全部满足才返回true。includes:判断数组是否包含某个值。flat:数组扁平化。from:把类数组转为数组。of:创建数组。
示例:
constarr=[1,2,3,4]constdoubled=arr.map(x=>x*2)// [2, 4, 6, 8]constevens=arr.filter(x=>x%2===0)// [2, 4]constsum=arr.reduce((acc,cur)=>acc+cur,0)// 1035. 图形用户界面 GUI 是什么
GUI(Graphical User Interface,图形用户界面)就是用图形方式显示和操作的用户界面,用户通过鼠标点击图标、按钮、菜单等与程序交互,而不是敲命令行。
前端每天做的网页、手机 App 界面、桌面软件界面,都属于 GUI。与之相对的是 CLI(命令行界面),比如终端、DOS。
简单说:GUI 就是咱们能“点”的界面,CLI 是咱们只能“敲”的界面。
总结
这 35 个问题覆盖了前端事件、网络、Vue、构建工具、大屏、ES6 等多个方向,都是面试和日常开发中高频出现的知识点。看完一遍可能记不住,建议收藏起来,面试前翻一翻,或者哪里忘了回来查。
如果你觉得有用,点个赞再走呗~