vue 2.0面试题

45 阅读9分钟

一:MVC 和 MVVM 区别

  1. MVC模式

    • Model:处理数据和业务逻辑,不直接处理视图。‌
    • View:负责界面展示,不包含业务逻辑。‌‌
    • Controller:接收用户输入,协调Model和View的交互,需手动更新视图。‌
  2. MVVM模式

    • Model:与MVC相同,处理数据和业务逻辑。‌
    • View:仅展示数据,通过数据绑定与ViewModel连接。‌
    • ViewModel:作为桥梁,封装视图逻辑,通过双向数据绑定自动同步Model和View的变化。 优缺点对比
  • MVVM优势:代码结构清晰,减少手动同步代码;劣势是数据绑定机制可能增加初学难度,且需框架支持。‌
  • MVC优势:架构成熟,适合小型项目;劣势是Controller易膨胀,维护成本随复杂度上升。‌ 选择时需根据项目需求:MVVM适合复杂前端应用,MVC在传统场景中仍具价值。‌

二. 为什么 data 是一个函数
组件中data写成一个函数,
①:数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的 data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
②:单纯的写成对象形式,就使得所有组件实例共用了一份 data,就会造成一个变了全都会变的结果.

三. Vue 组件通讯有哪几种方式
①. 父组件向子组件传数据通prop传递 子组件传递数据给父组件通过 $emit 触发事件做到.

②. parent,parent, children 获取当前组件的父组件和当前组件的子组件.

③. attrsattrs 和 listeners A->B->C。Vue 2.4 开始提供 attrsattrs 和 listeners 解决这个问题.

④. 父组件通过provide提供变量,子组件通过inject注入变量(官方不推荐实际业务中使用,写组件库时常用).
⑤. $refs 获取组件实例.
⑥. eventBus 兄弟组件数据传递 这种情况下可以使用事件总线方式.
⑦. vuex 状态管理.

四. v-if 和 v-show 的区别
v-if 在编译过程中会被转化成三元表达式,条件不满足时不渲染此节点。
v-show 会被编译成指令,条件不满足时控制样式将对应节点隐藏 (display:none)。

使用场景 v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景
v-show 适用于需要非常频繁切换条件的场景

五. 怎样理解 Vue 的单向数据流

①:数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数据进行修改。 ②:如果要改变父组件中的值,可以用$emit 通知父组件去修改。

六. v-if 与 v-for 为什么不建议一起使用

v-for 和 v-if 不要在同一个标签中使用,因为解析时先解析 v-for 再解析 v-if。如果遇到需要同时使用时可以考虑写成计算属性的方式。

七. computed 和 watch 的区别和运用的场景

①:computed是计算属性,依赖其他属性计算值,并且computed值有缓存,只有当计算值变化才会返回内容,它可以设置 getter 和 setter。 ②:watch监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。

区别: 计算属性一般用在模板渲染中,某个值是依赖了其它的响应式对象甚至是计算属性计算而来; 而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑

八.虚拟 DOM 是什么? 有什么优缺点?

虚拟DOM是前端框架(如React、Vue)中用于优化UI渲染的一种技术,它是一个轻量级的JavaScript对象,用以描述真实DOM树的结构、属性和子元素,作为真实DOM的内存中抽象表示。‌

虚拟DOM的核心优势在于性能优化、开发体验提升和跨平台能力。 ‌ 具体来说:

  • 性能优化‌:通过在内存中操作虚拟DOM树并使用diff算法计算最小差异,减少对真实DOM的直接操作,从而降低重排和重绘频率,提升渲染效率。
  • 开发体验提升‌:采用声明式编程范式,将UI逻辑与渲染过程分离,使代码更清晰、可维护性更高,并支持组件化开发,增强代码复用性。
  • 跨平台能力‌:作为与平台无关的抽象层,虚拟DOM可适配Web、移动端(如React Native)和服务器等环境,实现代码复用。‌

然而,虚拟DOM也存在一些缺点。 ‌ 主要包括:

  • 额外内存开销‌:虚拟DOM树需在内存中维护,会增加应用的内存占用。
  • 对简单场景的适用性有限‌:在静态内容或首屏加载敏感的场景中,虚拟DOM的计算开销可能超过其收益。
  • 学习曲线与集成挑战‌:开发者需理解其工作原理(如Key属性的使用),且与某些依赖直接DOM操作的库(如D3.js)集成时可能存在兼容性问题。‌

九.#### v-model的实现原理?

v-model 的实现原理是依赖于 Vue 的v-bind指令 和 @input 特性:v-model 实际上是一个语法糖,在 ⼀个组件上使⽤ v-model ,默认会为组件绑定名为 value 的 prop 和名为 input 的事件。

js:中input事件+this.$emit实现数据双向绑定.

image.png

十.v-for 为什么要加 key?

①:核心作用是优化虚拟DOM更新和提升性能。 ‌ Vue使用diff算法比较新旧虚拟DOM树,key作为节点的唯一标识,帮助算法精确识别元素的增删改,避免就地复用策略导致的不必要的DOM操作。例如,当列表顺序变化时,key能确保DOM元素正确复用,减少重渲染开销。‌

②:key还能保持组件状态和确保正确渲染。 ‌ 对于包含临时状态(如表单输入、动画)的组件,key确保状态与特定数据项绑定,防止更新时状态错乱。同时,key避免渲染错误,如列表顺序错乱或元素错位。‌

③:key应使用稳定且唯一的标识符,避免使用数组索引。 ‌ 推荐使用数据项的唯一ID等稳定值作为key,因为索引在列表变化时可能失效,导致不必要的DOM重新创建。‌

④:官方强调key的重要性。 ‌ 在Vue 2.x中,使用v-for渲染动态子节点或组件时,若未绑定key会触发警告。‌‌

十一. 谈一下对 vuex 的个人理解

vuex 是专门为 vue 提供的全局状态管理系统,用于多个组件中数据共享、数据缓存等(无法持久化、内部核心原理是通过创造一个全局实例 new Vue)

主要包括以下几个模块:

  • State:里面存放的是响应式的数据。
  • Getter:State进行计算操作,在多个组件间复用。
  • Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
  • Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
  • Module:Vuex允许我们将store分隔成模块。

十二. Vuex 页面刷新数据丢失怎么解决

需要做 vuex 数据持久化 一般使用本地存储方案来保存数据 可以自己设计存储方案 也可以使用第三方插件

推荐使用 vuex-persist 插件,它就是为Vuex持久化存储而生的一个插件。不需要手动存取storage ,而是直接将状态保存至cookie 或者 localStorage 中

十三. 使用过 Vue SSR 吗?说说 SSR

SSR 也就是服务端渲染,也就是将 Vue 在客户端把标签渲染成 HTML 的工作放在服务端完成,然后再把 html 直接返回给客户端。

优点: SSR 有着更好的 SEO、并且首屏加载速度更快

缺点:  开发条件会受到限制,服务器端渲染只支持beforeCreate和created两个钩子,当我们需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于 Node.js 的运行环境。

服务器会有更大的负载需求

十四. 你都做过哪些 Vue 的性能优化

编码阶段

  • 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
  • v-if和v-for不能连⽤
  • 如果需要使⽤v-for给每项元素绑定事件时使⽤事件代理
  • SPA ⻚⾯采⽤keep-alive缓存组件
  • 在更多的情况下,使⽤v-if替代v-show
  • key保证唯⼀
  • 使⽤路由懒加载、异步组件
  • 防抖、节流
  • 第三⽅模块按需导⼊
  • ⻓列表滚动到可视区域动态加载
  • 图⽚懒加载

SEO优化

  • 预渲染
  • 服务端渲染SSR

打包优化

  • 压缩代码
  • Tree Shaking/Scope Hoisting
  • 使⽤cdn加载第三⽅模块
  • 多线程打包happypack
  • splitChunks抽离公共⽂件
  • sourceMap优化

⽤户体验

  • 骨架屏
  • PWA

还可以使⽤缓存(客户端缓存、服务端缓存)优化、服务端开启gzip压缩等。

十五. 能说下 vue-router 中常用的路由模式实现原理吗?

hash 模式

①: location.hash 的值实际就是 URL 中#后面的东西 它的特点在于:hash 虽然出现 URL 中,但不会被包含在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
②:可以为 hash 的改变添加监听事件
每一次改变hash(window.location.hash)都会在浏览器的访问历史中增加一个记录. 利用hash的以上特点,就可以来实现前端路由“更新视图但不重新请求页面”的功能了
特点:兼容性好但是不美观.

history 模式

利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。

这两个方法应用于浏览器的历史记录站,在当前已有的back、forward、go 基础之上,提供了对历史记录修改的功能。这两个方法有个共同特点:当调用他们修改浏览器历史记录栈后,虽然当前URL改变了,但浏览器不会刷新页面,这就为单页应用前端路由“更新视图但不重新请求页面”提供了基础。

特点:虽然美观,但是刷新会出现 404 需要后端进行配置

十六.vue生命周期 在VUE中每个组价都是独立的,每个组件都有属于自己的生命周期,从一个组件的创建、数据初始化、挂载、更新、销毁、这就是一个组件所谓的生命周期。
生命周期的8个钩子函数分别为

实例创建之前:beforeCreate(){},把传入的data属性的内容,赋给vue对象。即:把形参中data的属性赋给vue对象,前后分别的钩子函数是:beforeCreate、created

实例创建后:created(){}

初始化之前:beforeMount(),把vue对象中data渲染到dom对象上,前后分别的钩子函数是:beforeMount、mounted

实例初始化:mounted(){}

数据同步前:beforeUpdata(){},当数据发生变化时,会触发组件的更新。

数据同步后:updata(){}

实例销毁前:beforeDestroy(){}

实例销毁后:destoryed(){}

如果组件在缓存的话,那么,组件切换时,会调用的钩子函数是: activated 和 deactivated

十七. 数组去重 ①.利用ES6 Set 去重(ES6中最常用,代码最少)

let arr = [4, 1, 3, 3, 2, '2'];
let uniqueArr = [...new Set(arr)];
console.log(uniqueArr); 

十八. 深拷贝和浅拷贝

浅拷贝:只是增加了一个指针指向已存在的内存地址
深拷贝:是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,

十九. 数组和字符串常见方法。

数组方法:

join(): 把数组放入字符串,默认逗号隔开,arr数组不变。

concat():连接数组,返回新的数组,arr数组不变。

slice(): 选取数组,返回选取的数组,arr数组不变。(第一个参数从哪里开始,第二个是截取到哪个(返回不包括),如果只有第一个参数0,都取。)

push(): 数组末尾增加元素,返回数组长度,arr为增加后的数组。

unshift()*数组开头增加元素,返回数组长度,arr为增加后的数组。

pop(): 数组末尾删除一个,返回删除的元素,arr为删除后的数组。

shift(): 数组开头删除一个,返回删除的元素,arr为删除后的数组。

splice(): 增、删、改都可以,返回增删改的元素,arr为增删改的元素。(第一个参数从哪里开始,第二个参数是删除的个数,后面的参数是增加的元素)

字符串的方法:(字符串有恒定性,修改字符串不会修改本身)

charAt(): 传入一个数组,返回选中位置的字符串,string字符串不变。

concat(): 传入增加的字符串,返回新的字符串,string字符串不变。

split(): 字符串分割为数组,返回新的数组,string字符串不变。

indexOf():字符串首次出现的位置,返回位置,没有返回-1, string字符串不变。(第一个参数是要检索的字符,第二个参数从哪里开始检索)

lastIndexOf(): 从后向前检索。但是下标还是从左往右算。

replace(): replace(‘b’, ‘B’),替换。

slice(): 跟数组方法类似。截取。

toLowerCase(): 字符串转为小写。

toUpperCase(): 字符串转为大写。