前端面试题1
vue基础
1、谈谈你对 SPA 单页面模式的理解,优缺点 ?(字节、广联达)
SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS
典型使用 SPA 模式的前端框架有:React、Angular、Vue
一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。
优点:
用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;
基于上面一点,SPA 相对对服务器压力小;
前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;
缺点:
初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载;
前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;
SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。
2、什么是 MVVM,特征,实现思路,解决了什么问题 ?(百度、字节)
简短一句话解释:
MVVM 是 Model-View-ViewModel 缩写,也就是把 MVC 中的 Controller 演变成 ViewModel
Model 层代表数据模型,View 代表 UI 组件,ViewModel 是 View 和 Model 层的桥梁,数据会绑定到 viewModel 层并自动将数据渲染到页面中,视图变化的时候会通知 viewModel 层更新数据。

3、Vue 什么特性表示出 MVVM 特性?(百度)
响应式数据绑定系统
数据层(Model):应用的数据及业务逻辑
视图层(View):应用的展示效果,各类UI组件
业务逻辑层(ViewModel):框架封装的核心,它负责将数据与视图关联起来
ViewModel主要职责:
1.数据变化后更新视图
2.视图变化后更新数据
ViewModel主要部分组成:
监听器(Observer):对所有数据的属性进行监听
解析器(Compiler):对每个元素节点的指令进行扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数

4、computed和watch的区别(源码上) ? (同花顺、快手)
computed 和 watch 的核心区别在于:computed 是依赖缓存的声明式计算属性,适用于多对一的数据关联场景;watch 是响应式监听器,支持异步操作和深度监听,适用于一对多的数据响应场景。
功能定位差异
computed
定义:基于响应式依赖自动计算新值,结果会被缓存。
特点:必须返回新值(必须有 return),计算结果可像普通属性直接使用。
示例应用:购物车总价计算、数据格式化(如价格格式转换)。
watch
定义:监听特定数据源的变化并执行副作用操作。
特点:支持异步操作、深度监听(deep:true)和立即执(immediate:true)。
示例应用:搜索框联动查询、表单数据异步校验。
核心机制对比
缓存机制:
computed 对计算结果进行缓存,仅当依赖项变化时重新计算。
watch 无缓存机制,每次监听值变化都会触发回调。
异步处理:
computed 函数内部禁止异步操作,必须同步返回计算结果。
watch 支持异步操作,适合执行网络请求等耗时任务。
初始化行为:
computed 默认立即计算并缓存初始值。
watch 默认不执行首次监听,需配置 immediate:true 实现首次加载监听。
5、nextTick的原理(底层实现)及使用场景 ? (同花顺、58、快手、阿里)
引用自:https://developer.aliyun.com/article/1451796
简介:
nextTick 是 Vue.js 提供的一个方法,用于在下一个 DOM 更新周期后执行一些操作。在 Vue.js 中,数据的更新是异步进行的,这意味着当我们修改了数据后,DOM 并不会立即更新。nextTick 允许我们在数据更新完成后执行一些操作,确保我们的操作基于最新的 DOM 状态。
原理
nextTick 的实现原理是异步延迟执行。当调用 nextTick 时,它会将所有的 DOM更新操作放入一个回调函数中,然后异步执行这个回调函数。这样,在执行回调函数时,DOM 已经更新完毕,可以正确地操作 DOM 元素。
nextTick 使用 Promise 和 MutationObserver 实现异步延迟执行。在现代浏览器中,MutationObserver 是一个异步的 DOM 监听器,它可以监听 DOM 变化并在变化发生时触发回调函数。Promise 则用于在异步操作完成后执行回调函数。
nextTick 的实现基于 JavaScript 的异步队列。
当我们在 Vue 实例中修改了数据后,Vue 会开启一个队列,并将需要更新的数据放入队列中。
在这个过程中,Vue 会执行当前的宏任务(macrotask),比如事件处理、动画帧等。
一旦当前宏任务执行完毕,Vue 会检查队列中的数据,如果发现有数据更新,则会执行 nextTick 中注册的回调函数。
适用场景
在数据更新后获取最新的 DOM 状态。
执行一些依赖于最新 DOM 状态的操作,比如计算布局变化、调整样式等。
在组件生命周期的某些阶段,确保某些操作在 DOM 更新后执行。
6、keep-alive的原理和使用场景? (同花顺)
引用自:https://blog.csdn.net/m0_51429350/article/details/148697008
简介
keep-alive 是 Vue 提供的一个内置组件,用于缓存动态组件的状态。它可以让组件在切换时不被销毁,从而保留当前状态(如表单输入、滚动位置等),提升用户体验和性能。
基本语法
<keep-alive> <component :is="currentComponent" /> </keep-alive>
- component :is=“…” 是 Vue 的动态组件机制。
- 会缓存该组件的实例,而不是每次都重新创建。
控制缓存组件
通过 include 和 exclude 属性可以控制哪些组件需要缓存:
| 属性 | 类型 | 描述 |
|---|---|---|
| include | string/RegExp/Array | 匹配的组件名会被缓存 |
| exclude | string/RegExp/Array | 匹配的组件名不会被缓存 |
示例:
<keep-alive include="Home,UserDetail"> <component :is="currentView" /> </keep-alive>
注意:组件必须有 name 属性才能被匹配。
| 钩子函数 | 触发时机 | 说明 |
|---|---|---|
| activated() | 组件被激活时调用(显示) | 可以在这里执行初始化或恢复操作 |
| deactivated() | 组件被缓存时调用(隐藏 | 可以在这里清理资源、取消定时器等 |
7、for…in和for…of的区别 ?(同花顺)
for…in 主要用于遍历对象的可枚举属性(键名),而 for…of 用于遍历可迭代对象(如数组、字符串等)的元素值(键值)。
遍历目标与返回值:
for…in:遍历对象的可枚举属性(包括自身和原型链上的属性),返回键名(key)。例如遍历数组时返回字符串形式的索引(如 ‘0’、‘1’),遍历对象时返回属性名。
for…of:遍历可迭代对象(实现了 [Symbol.iterator] 接口的数据结构),直接返回元素值(value),如数组的元素、字符串的字符等。
适用数据类型:
for…in:适用于普通对象(Object),可遍历数组但不推荐(可能意外包含原型链或自定义属性)。
for…of:适用于数组、字符串、Map、Set、NodeList 等可迭代对象,但不能直接遍历普通对象(需手动实现迭代器)。
原型链与性能:
for…in:会遍历原型链上的可枚举属性,需通过 hasOwnProperty 过滤;性能较差,因需检查原型链。
for…of:仅遍历对象自身的元素,不涉及原型链,性能更优。
8、import和export的区别 ? (同花顺)
1.export 与 export default 均可用于导出常量、变量、函数、文件、模块等;
2.在一个文件或模块中,export、import可以有多个,但 export default 仅有一个;
3.通过export方式导出,在导入(import)时要加花括号{ },export default 则不需要 { }。
使用 export 导出的变量需要用 {} 进行导入
export和export default最大的区别就是export不限导出的变量数,可以一直写,在同一个js文件中可以有多个,而 export default 只输出一次,在同一个js文件中只能有一个。而且 export导出的变量想要导入使用必须使用大括号 {} 来盛放,而export default 不需要,只要 import 任意一个名字来接收对象即可。
9、说一下 js 的 import 和 node 的 require 的区别(字节)
- 语法
• require 是 CommonJS 的模块引入方式,语法为:const module = require(‘module’)
• import 是 ES6 的模块引入方式,语法为:import module from ‘module’ - 动态加载
• require 是动态加载模块的,可以在代码的任何地方使用
• import 是静态加载模块的,只能在文件的顶部使用 - 导出方式
• require 是通过 module.exports 导出模块的
• import 是通过 export 导出模块的
10、说说对自定义指令的理解 ?写一个 vue 的自定义指令(同花顺、快手)
Vue 的自定义指令允许开发人员在 DOM 元素上添加自定义行为。自定义指令可以用于操作 DOM、监听事件、修改样式等。使用自定义指令,您可以将特定的交互逻辑封装成一个可重用的指令,并在需要时在应用程序中应用它。
Vue 自定义指令的常见钩子函数包括:
bind: 指令第一次绑定到元素时触发
inserted: 元素被插入到父元素时触发
update: 指令所在的模板被重新解析时触发
componentUpdated: 组件更新完成时触发
unbind: 指令与元素解绑时触发
11、说一下 v-modle 的原理 (58、百度)
编译阶段:在模板编译阶段,v-model指令被解析为一个包含多个属性和方法的对象。其中最重要的属性是value,它绑定了需要双向绑定的数据属性。同时,v-model还会创建一个观察者来观察这个数据属性。
渲染阶段:在组件渲染阶段,v-model指令会创建一个Watcher对象来监听绑定的数据属性变化。这个Watcher对象会在数据属性的初始值被设置时进行依赖收集,以便在后续的数据属性变化时能够通知其他依赖该属性的组件重新渲染。
数据变化检测:当绑定的数据属性发生变化时,观察者会自动检测到这种变化并将该数据属性标记为脏数据。此时,Dep类会通知所有依赖该属性的Watcher对象重新渲染相关的组件。
更新视图:Watcher对象收到数据属性变化通知后,会执行相应的回调函数来更新视图。这个回调函数通常会重新计算组件的虚拟DOM并更新DOM树,使得视图能够实时反映数据的变化。
用户输入处理:当用户在输入框中输入内容时,浏览器会自动将输入内容赋值给input元素绑定的value属性。由于v-model指令绑定了这个value属性,因此当用户输入内容时,绑定的数据属性会自动更新。同时,由于v-model实现了双向绑定,因此观察者能够检测到这种变化并触发重新渲染操作,使得视图能够实时更新。
总结:
v-model作为Vue.js中的一个重要指令,其核心作用是实现双向数据绑定。通过指令系统、观察者、Dep类和Watcher类的协同工作,v-model能够自动检测数据的变化并更新视图,使得前端开发人员能够更加便捷地实现用户界面和数据之间的双向同步。
12、说一下 v-if 和 v-show 的区别和使用场景(商汤、字节、快手)
引用自https://blog.csdn.net/2203_75479159/article/details/147398964
v-show和v-if都是 Vue.js 框架里用于控制元素在页面上显示与隐藏的指令。
| 特性 | v-if | v-show |
|---|---|---|
| 渲染机制 | 条件为真时渲染元素,否则销毁 | 始终渲染元素,通过 CSS 控制显示 |
| DOM 操作 | 动态添加/移除 DOM 元素 | 仅切换 display: none 样式 |
| 初始开销 | 低(条件为假时不渲染) | 高(无论条件如何都渲染) |
| 切换开销 | 高(涉及组件销毁/重建) | 低(仅修改 CSS 属性) |
| 组件生命周期 | 触发 created/mounted 等钩子函数 | 不触发生命周期钩子(始终存在) |
使用场景
✅ 使用 v-if 的场景:
初始条件不满足时:如权限控制下隐藏敏感内容
元素包含复杂子组件:避免隐藏时仍占用内存
不频繁切换的组件:如页面初始化时决定是否加载某个模块
✅ 使用 v-show 的场景:
频繁切换显示状态:如选项卡切换、折叠面板
需要保持组件状态:如表单输入保留值
元素渲染成本低:简单 DOM 元素无需优化初始加载
13、v-if 和 v-for 的优先级?为什么不建议在同一元素上使用?(货拉拉)
v-for 优先级比 v-if 高
永远不要把 v-if 和 v-for 同时用在同一个元素上,带来性能方面的浪费(每次渲染都会先循环再进行条件判断)
如果避免出现这种情况,则在外层嵌套template(页面渲染不生成dom节点),在这一层进行v-if判断,然后在内部进行v-for循环
<template v-if="isShow"><p v-for="item in items">
</template>
如果条件出现在循环内部,可通过计算属性 computed 提前过滤掉那些不需要显示的项
computed: {
//过滤出满足条件后的数据再渲染items: function() {return this.list.filter(function (item) {return item.isShow})}
}
14、什么是双向绑定 ?(同花顺)
引用自https://blog.csdn.net/He_9a9/article/details/132846209
Vue中的双向绑定是一种机制,它实现了模型(Model)和视图(View)之间的动态交互。当Model或View发生变化时,另一个也会相应地更新。这是通过数据劫持和发布订阅模式实现的。
数据层(Model):应用的数据及业务逻辑
视图层(View):应用的展示效果,各类UI组件
业务逻辑层(ViewModel):框架封装的核心,它负责将数据与视图关联起来
ViewModel主要职责:
1.数据变化后更新视图
2.视图变化后更新数据
ViewModel主要部分组成:
监听器(Observer):对所有数据的属性进行监听
解析器(Compiler):对每个元素节点的指令进行扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数

15、Vue2 无法监听数组的哪些操作 ?如何解决? (同花顺)
Vue 2 可以追踪数组的部分变更:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
不能追踪的变更方式:
1.通过索引直接修改数组元素:
this.items[1] = 'new value' // 不会触发视图更新!
2.直接设置数组长度:
this.items.length = 1 // 也不会触发更新
解决方案
- 使用 Vue.set() 或 this.$set()
this.$set(this.items, 1, 'new value')
//或者
Vue.set(this.items, 1, 'new value')
- 使用数组方法如 splice
在 Vue 3 中,响应式系统使用了 Proxy,能够直接监听所有数组变化,包括索引设置和 .length 变更,因此这些问题在 Vue 3 已经不存在。
16、Vue 里面的 computed 和 data 里面的值有什么区别吗?具体原理实现有什么区别?(腾讯)
数据依赖性
data:存储原始数据,是组件的私有数据,每个组件实例的data数据是独立的。
computed:依赖data中的数据,通过计算得到新值。当依赖的data数据变化时,computed会自动更新。
缓存机制
computed:计算结果会被缓存,只有当依赖的data数据变化时才会重新计算。
data:存储原始数据,不自动缓存计算结果。
实现原理
computed:通过Object.defineProperty()实现依赖追踪,当依赖的响应式数据变化时,触发重新计算。
data:通过函数返回对象的方式实现数据隔离,避免组件复用时的数据污染。
性能差异
computed:通过缓存减少重复计算,提升性能。
data:每次访问都需要重新获取,性能较低。
17、Vue data 为什么是函数(阿里)
在Vue组件中,data选项如果不是一个函数,而是一个普通的对象,会导致每个组件实例共享同一个数据对象。这可能会引发一些意想不到的问题,因为每个组件实例都会修改同一个数据对象,从而影响其他组件实例的数据。
当data选项是一个函数时,它会返回一个新的数据对象,这样每个组件实例都拥有自己独立的数据副本,相互之间不会互相影响。
18、了解 vue 的 mixin 和 extend 吗 ?(快手)
使用场景:
mixin:通用逻辑共享:当多个组件需要共享相同的方法,数据和属性时,可以通过mixin实现
extend:如果想基于现有组件创建一个新组件,并且新组件还能继承现有组件的数据,方法和属性时,可以通过extend实现
mixin
(1)针对钩子函数:同名钩子函数不会被覆盖,会合并到一起,并且都被调用,但混入的钩子函数将在组件本身额钩子函数之前被调用
(2)针对对象:例如data,computed,methods等,同样会被合并到一起,如果混入的对象属性名称和组件本身的冲突,最终取组件本身的属性键值对
(3)一个组件可以混入多个mixin对象,当多个混入对象中有属性名冲突时,则后引入的会覆盖前面引入的;但是钩子函数不会被覆盖,仍然全部都被调用,且按混入的先后顺序被调用
继承规则:extend和mixin不同,不执行选项的合并或者混合,而是直接覆盖,例如 B组件 继承 A组件,一旦B组件中新增的data数据,computed,method等对象属性和A组件的冲突,则B覆盖A;
钩子函数和mixin一样合并到一起,且extend的钩子函数先被调用
当一个组件中同时使用了extend和mixin时,其优先级为: extend > mixin > 组件本身; 钩子函数也是按这个优先级被调用
19、如何理解 Vue 的单向数据流 ?(同花顺)
在父子组件中,通过prop来进行数据传输,所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
20、在 Vue 中,设置全局变量的方式有哪些 ? (同花顺)
1、Vue.prototype.global = ‘全局变量’
2、Vue.use()允许你拥有插件遍历,插件是一个接受vue构建函数参数作为函数参数或者一个包含install函数并设置vue插件的对象
3、通过Vue.mixin({ props: { type: String, default: '全局变量 } })
4、import { global } from ‘**.js’
