前端vue相关常见面试题,包含MVVM、双向绑定原理、性能优化、vue2和vue3性能对比等

vue面试题

MVVM

  1. 概念

    model view viewModel

    本质上是mvc(程序分层开发思想)

    将viewModel的状态和行为抽象化,viewmodel将视图ui和业务逻辑分开,去除model的数据,同时处理view中需要展示的内容和业务逻辑

  2. view视图层

    html和css构成

    展示页面和承载数据

  3. model数据模型

    axios请求的部分、数据和业务逻辑的处理

    后端进行数据操作和业务逻辑处理

  4. viewModel视图模型

    前端人员生成和维护 视图和数据层,承上启下

    处理view上的事件和输入,转化为对model的操作;model层获取数据,在view层进行数据处理、重构、渲染

  5. MVVM特点

  • 低耦合,内容可以独立分成单独模块,model和view互不影响

  • 可复用性较强

  • 分层开发,提高开发效率

  • 测试容易

  • 增加了应用程序的复杂性,双向数据绑定可能造成额外的开销

单页面应用

  1. 概念

    SPA,加载单个html页面,在用户与应用程序交互时,动态更新页面

  2. 工作原理

  • 浏览器发送请求,服务器返回index.html
  • index.html中的js脚本控制显示页面
  • 通过路由,在页面显示不同的模板和数据,调用切换仅返回json数据
  • 应用程序通过json动态更新页面,页面不会重新加载
  1. 优点
  • 前后端分离,开发效率高
  • 用户体验好,无需重新加载页面,同一套后端程序可以支持web、手机等
  • 组件化,可复用性
  • 减轻服务器压力
  1. 缺点
  • 首页加载较慢
  • 导航功能无法使用浏览器自带的页面前进、后退
  • 不利于SEO(因为页面内容是异步请求显示的)

vue2和vue3的区别

双向绑定数据的原理不同

  1. vue2:通过Object.defineProperty实现
js 复制代码
//数据更新,但是视图没更新
//添加下面的代码用来更新视图
this.$set(this.data, 'name', 'newName')
  1. vue3:通过Proxy实现

  2. defineProperty和Proxy的异同

  • defineProperty改变对象的内部属性描述符
  • proxy创建新代理对象,对原始对象的操作都重定向到这个代理对象上
  • defineProperty只能修改对象本身,而proxy可以修改对象本身和原型链上的属性

生命周期不同

  1. vue2:beforeCreate created beforeMount mounted beforeUpdate updated beforeDestory destroyed

  2. vue3:setup onBeforeMount onMounted onBeforeUpdate onUpdated onBeforeUnmount onUnmounted

keep-alive中多两个钩子函数

onActivated

onDeactivated

父子传值不同

  1. vue2:props this.$emits
  2. vue3:props defineEmits

API选型不同

  1. vue2是选项式API,代码中分割不同属性 data methods computed ...
  2. vue3是组合式API

vue3支持多根节点,vue2只支持单根节点

数据定义

vue2在data中定义,vue3使用ref或reactive

数据双向绑定原理

了解常用方法

  1. reduce
  • 参数:(第一个值/上次计算的结果,当前项目,当前项目下标,调用的数组)

  • 求和

    const total=arr.reduce((a,b)=>a+b)

  • 链式获取对象属性

js 复制代码
const a=arr.reduce((newObj,k)=>{
  //每次调用之后的newObj都是上一次返回的结果
  return newObj[k]
})
  • 发布订阅模式

  • 名词

    setter属性 -> set方法 有参,无需return

    getter属性 -> get方法 无参

    用来访问和设置对象的属性

  • object.defineProperty

    可以定义新属性或修改原有属性

    参数:defineProperty(目标对象,属性名,特性)

js 复制代码
Object.defineProperty(obj,'name',{
    //当前属性可以被循环遍历
    enumerable:true,
    //当前属性允许被设置
    configurable:true,
    //get方法
    get(){
        return 1
    },
    //set
    set(newVal){
        console.log('set',newVal)
    }
})

在设置或获取属性的时候,自动调用其中的get和set方法

33:54

插槽

  1. 概念:决定将所携带的内容插入到某个指定的位置,模板在父组件中定义,传递到子组件显示

  2. 默认插槽

  3. 具名插槽

  4. 作用域插槽

    数据在子组件上,但是表现由父组件决定

<template #name="{data}">

混入mixin

  1. 概念:可复用的代码片段,包含函数/功能/辅助的业务逻辑,写在单独的文件中

  2. 使用

    定义在src/mixins/minxin.js中,导出function

在组件中导入mixin,解构其中值,可以读取数据和调用函数

注意:混入中的数据不共享

  1. 优点:使用方便,减少重复代码,可以实现复杂的业务逻辑

  2. 缺点:组件之间不能共享数据;混入的变量和方法很难找到来源;多个mixin容易引起冲突

nextTick

  1. 概念:下次DOM更新循环结束之后,延迟回调函数执行

  2. 异步更新队列

    vue观察到更新数据后,不是直接更新dom,而是开启队列,缓存数据并去重,避免不必要的计算和更新

keep-alive

  1. 缓存组件,避免重复渲染

  2. 优势:组件切换过程中将状态保存在内存中,防止重复渲染DOM,减少加载时间和性能消耗,提高用户体验

  3. 使用router-view

html 复制代码
<!-- vue3写法 -->
<router-view v-slot="{Component}">
  <!-- 控制只缓存home -->
  <keep-alive include="homt">
    <Component :is="Component" />
    </keep-alive>
</router-view>
  1. 控制缓存页面

    include:只缓存xx

    exclude:排除xx

    max:最大缓存数

  2. 激活新钩子函数

  • onActivated 激活组件时
  • onDeactivated 停用组件时

vuex和pinia

vuex使用

  1. 基础
js 复制代码
import { useStore } from 'vuex'
const store = useStore()

调用mutation 要用commit

调用action 要用dispatch

数据持久化使用vuex-persistedstate

  1. 常用方法
    state:数据源
    getters:返回被依赖的数据
    mutations:同步更新数据源
    actions:异步更新数据源
    module:对多模块进行管理

pinia使用

  1. 基础使用
js 复制代码
import {defineStore} from 'pinia'

export default defineStore('name',()=>{
  const name="jack"

  return {
    name
  }
},{
  //持久化
  persist:true
})

vuex和pinia的区别

  1. 方法区别

    vuex:state getters mutations actions module

    pinia:state getters actions

  2. pinia调用更方便,可以直接对数据进行读写,不需要commit和dispatch

  3. vuex中缺少模块属性支持,pinia中支持

  4. pinia有更好的ts支持

vue源码

目录分析

  1. src/compiler 模板解析和编译相关的文件
  2. src/core 核心文件,包括vue架构、内置组件、全局API封装等
  3. src/platforms 平台相关文件
  4. src/server 服务端渲染相关文件
  5. src/sfc .vue的解析文件
  6. src/shared 公共工具

过程

  1. npm run server之后,创建一个new Vue实例 --> 最核心是用到了instance/index

  2. function vue 为什么不是class,因为有mixins或其他的公共方法,都在vue.prototype上,而new Vue实例,就相当于一个对象,所以用function

  3. 三种渲染方式:render template el,最终都得到render函数

    render函数通过watcher绑定,数据发生变化时,执行update方法,调用vm._render(),产生虚拟DOM,patch对比新旧vnode,diff算法增删改真正的DOM元素

  4. instance/init做了什么

  • 为当前vue实例(vm)添加唯一uid
  • vm._isVue设置为true(监听对象变化时过滤vm)
  • 初始化组件
  • 初始化各种内容,包括生命周期,事件,虚拟DOM等
  • 如果有el属性,就调用vm.$mount挂载vue实例

vue渲染小结

  1. new vue执行初始化
  2. 挂载$mount,通过render函数生成渲染树
  3. watcher监听数据变化
  4. 数据变化时,render函数生成vnode
  5. 通过patch对新旧node进行比较,通过diff算法,增删改dom

为什么vue3性能比vue2好

  1. vue3向下兼容vue2,官方测试:vue3打包速度比vue2快41%,初次渲染提升50%,内存使用减少50%;一些基础API和方法进行了优化
  2. vue3在setup中的函数和变量优化了程序副作用
  3. vue2劫持数据使用defineProperty+发布订阅模式实现,数组和新增属性需要额外开销;vue3使用proxy进行数据代理,实现整个对象进行响应式观测,数据变化不需要额外开销
  4. vue3在依赖手机、程序运行做了性能优化,还增加了异步渲染和懒加载的特性

代理和环境变量

  1. 代理:接口数据请求中,由于违反同源策略,导致cors跨域问题,需要配置代理,在vue.config.js中,添加devserver配置项及参数

  2. 环境变量:开发中使用开发环境,打包上线后使用生产环境

    process.env.环境变量名称

computed和watch

  1. computed计算属性
    必须有返回值,不支持异步,返回值会缓存,初始化会执行
js 复制代码
const nums=computed(()=>{
  return num.value*2
})
  1. watch
    被监听的数据变化时,watch执行,初始化不会执行
js 复制代码
watch(num,(newValue,oldValue)=>{
  console.log(oldValue,newValue)
})
  1. 区别
  • computed必须有return,watch无需
  • computed不支持异步,watch支持
  • computed初始化执行,watch不执行
  • computed会缓存数据,watch不会

vue2和vue3响应式的区别

  1. vue2:defineProperty+发布订阅模式实现
    在对象上定义新属性或修改现有对象的属性
    三个参数:target,key,descriptor
    Object.defineProperty(定义属性的对象,属性名称,属性描述)

缺点:递归遍历对象属性,消耗大;新增或删除属性不能立即响应,需要通过额外的方法(比如this.$set);数组修改也需要额外方法

  1. vue3:proxy实现
    拦截对象中任何属性变化,可以随时监听
    需要两个参数 proxy(代理的目标对象,对象的handler处理函数)
    实现了深层检测

formily自定义组件,子组件通知父组件更改数据

  1. 使用formily的field.set方法直接设置当前表单域的值,并通知父组件更新
  2. 使用vue的v-model绑定子组件,子组件通过props的modelValue和emit方法通知父组件更新
  3. 使用attrs的listeners,通知父组件更新
    listeners存储所有未被声明为prop的事件监听器
    底层是基于js的事件机制和proxy实现,vue在编译阶段收集事件监听器,运行时通过attrs.listeners触发

diff算法

  1. 应用场景:虚拟dom渲染为真实dom的新旧VNode节点比较

  2. 比较方式:深度优先、同层比较

  3. 原理:数据发生变化时,set调用Dep.notify通知订阅者,订阅者调用patch给真实的DOM打补丁

  • 如果isSameVnode相同,调用patchVnode

vue性能优化

  1. 选用正确的架构,避免部署纯客户端的SPA(存在首屏加载缓慢的问题),可以通过SSR或SSG缓解
  2. 压缩js打包文件体积,许多vue的API是可以被tree-shake的;按需引入依赖项
  3. 代码分割:构建工具将js包拆分为多个小的,可以按需加载或并行加载的文件,vite默认支持
  4. props稳定性:vue组件中,一个子组件只会在至少一个props改变时才更新
    比如一个list列表,其中很多listitem组件,根据active-id判断当前组件是否是选中的激活组件,如果active-id改变,每个组件都会重新更新!可以改为 :active="item.id === activeId"
  5. v-once 只渲染一次,不响应数据变化,v-memo跳过大型子树或v-for列表更新
  6. 列表虚拟化,比如vue-virtual-scroll
  7. 减少大型不可变数据的响应性开销,可以通过shallowRef 和 shallowReactive 来绕开深度响应
  8. 避免不必要的组件抽象,组件实例比普通DOM节点昂贵的多
相关推荐
我要洋人死1 小时前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人1 小时前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人1 小时前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR1 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596931 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai1 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_9152 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼3 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
逐·風7 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#