2025年vue2(vue2和vue3区别面试题)

vue2(vue2和vue3区别面试题)svg xmlns http www w3 org 2000 svg style display none svg

大家好,我是讯享网,很高兴认识大家。



 <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path> </svg> <p></p> 

讯享网


讯享网
M - Model 数据:它是与应用程序的业务逻辑相关的数据的封装载体
V - View 视图:它专注于界面的显示和渲染
VM - ViewModel 视图-数据:它是View和Model的粘合体,负责View和Model的交互和协作
vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;
核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法,get set 方法。
MVVM最标志的特性是数据绑定,核心理念是通过申明式的数据绑定实现View层和其它层的分离。完全解耦View层这种理念,也是的Web前端的测试用例编写变得简单。
MVVM 最重要的一个特征就是数据双向绑定, 而 React 是单向数据流, 状态驱动视图, 它没有纯粹意义上的 VM, 它有的只是用属性和状态去映射视图, 很明显不是 MVVM. 顶多也就是 MVVM 中的 V 层.对于 Vue从技术上讲,Vue.js 主要关注 MVVM 模式的 ViewModel 层, 它通过双向数据绑定连接视图和模型, 它更像是 MVVM 但并未完全按照 MVVM 去实现, 只是借鉴了 MVVM 中的一些思想.
在MVVM的框架下视图和模型是不能直接通信的。它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信








• M - Model 数据:数据实体,用来保存页面要展示的数据。比如ajax获取的数据。
• V - View 视图,显示数据的页面,一般为html。
• C - Controller 控制器: 控制整个业务逻辑,负责处理数据,比如数据的获取,以及数据的过滤,进而影响数据在视图上的展示。
MVC是应用最广泛的软件架构之一,一般MVC分为:Model(模型),View(视图),Controller(控制器)。 这主要是基于分层的目的,让彼此的职责分开.View一般用过Controller来和Model进行联系。Controller是Model和View的协调者,View和Model不直接联系。基本都是单向联系。M和V指的意思和MVVM中的M和V意思一样。C即Controller指的是页面业务逻辑。MVC是单向通信。也就是View跟Model,必须通过Controller来承上启下。


“MVVM与MVC的区别有:1、mvvm各部分的通信是双向的,而mvc各部分通信是单向的;2、mvvm是真正将页面与数据逻辑分离放到js里去实现,而mvc里面未分离。”
MVC允许在不改变视图的情况下改变视图对用户输入的响应方式,用户对View的操作交给了Controller处理,在Controller中响应View的事件调用Model的接口对数据进行操作,一旦Model发生变化便通知相关视图进行更新。
具体的演变流程:传统MVC ——> MVP ——> MVVM

1. 响应式系统的重构,使用proxy替换Object.defineProperty属性,优势:

讯享网

2. 新增(Composition API),更好的逻辑重用和代码组织:

 

3. 重构虚拟 DOM, diff算法

4. 生命周期更名

Vue3.0提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:

beforeCreate ===&gt; setup()

created ===&gt; setup()

beforeMount ===&gt; onBeforeMount

mounted ===&gt; onMounted

beforeUpdate ===&gt; onBeforeUpdate

updated ===&gt; onUpdated

beforeUnmount===&gt; onBeforeUnmount

unmounted ===&gt; onUnmounted

5. 新的内置组件: Fragment,Teleport,Suspense

6. 移除:

讯享网

  • 对象类型:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)
  • 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
  • 存在问题:

1.新增属性、删除属性, 界面不会更新。

2.直接通过下标修改数组, 界面不会自动更新。

补充:vue2中$set可以解决这些问题。

  • 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、添加、删除等。
  • 通过Reflect(反射): 对源对象的属性进行操作。
 

a. defineProperty API 的局限性最大原因是它只能针对单例属性做监听。

Vue2.x中的响应式实现正是基于defineProperty中的descriptor,对 data 中的属性做了遍历 + 递归,为每个属性设置了 getter、setter。
这也就是为什么 Vue 只能对 data 中预定义过的属性做出响应的原因,在Vue中使用下标的方式直接修改属性的值或者添加一个预先不存在的对象属性是无法做到setter监听的,这是defineProperty的局限性。
b. Proxy API的监听是针对一个对象的,那么对这个对象的所有操作会进入监听操作, 这就完全可以代理所有属性,将会带来很大的性能提升和更优的代码。

生成 Block tree

Vue.js 2.x 的数据更新并触发重新渲染的粒度是组件级的,单个组件内部 需要遍历该组件的整个 vnode 树。
在2.0里,渲染效率的快慢与组件大小成正相关:组件越大,渲染效率越慢。并且,对于一些静态节点,又无数据更新,这些遍历都是性能浪费。
Vue.js 3.0 做到了通过编译阶段对静态模板的分析,编译生成了 Block tree。
Block tree是一个将模版基于动态节点指令切割的嵌套区块,每个 区块内部的节点结构是固定的,每个区块只需要追踪自身包含的动态节点。
所以,在3.0里,渲染效率不再与模板大小成正相关,而是与模板中动态节点的数量成正相关。



slot 编译优化

Vue.js 2.x 中,如果有一个组件传入了slot,那么每次父组件更新的时候,会强制使子组件update,造成性能的浪费。
Vue.js 3.0 优化了slot的生成,使得非动态slot中属性的更新只会触发子组件的更新。
动态slot指的是在slot上面使用v-if,v-for,动态slot名字等会导致slot产生运行时动态变化但是又无法被子组件track的操作。

diff算法优化

性能更好

体积更小

更好地 ts 支持

更好的代码组织

更好的逻辑抽离

更多新的功能

1、性能提升

响应式性能提升,由原来的 Object.defineProperty 改为基于ES6的 Proxy ,使其速度更快,消除警告。

重写了 Vdom ,突破了 Vdom 的性能瓶颈。

进行模板编译优化。

更加高效的组件初始化。

2、更好的支持 typeScript

有更好的类型推断,使得 Vue3 把 typeScript 支持得非常好。

3、新增Composition API

Composition API 是 vue3 新增的功能,比 mixin 更强大。它可以把各个功能模块独立开来,提高代码逻辑的可复用性,同时代码压缩性更强。

4、新增组件

Fragment 不再限制 template 只有一个根几点。

Teleport 传送门,允许我们将控制的内容传送到任意的 DOM 中。

Supense 等待异步组件时渲染一些额外的内容,让应用有更好的用户体验。

5、Tree-shaking:支持摇树优化

摇树优化后会将不需要的模块修剪掉,真正需要的模块打到包内。优化后的项目体积只有原来的一半,加载速度更快。

6、Custom Renderer API: 自定义渲染器

实现 DOM 的方式进行 WebGL 编程。

setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显示的定义它们。其他的钩子都可以编写到 setup 内。

值得注意的是组合式API中的钩子函数,通过在生命周期钩子前面加上 “on” 来访问组件的生命周期钩子,需要注册,并且只能在 setup 期间同步使用,因为它们依赖于内部的全局状态来定位当前组件实例。

vue2 中我们把一个 vue 文件中 data、methods、props、mounted、computed 等定义属性和方法,共同处理页面逻辑,这种方式叫做 Options API。

这种方式开发的复杂组件,同一个功能的往往需要在不同 vue 配置项中定义属性和方法,代码比较分散。如果功能比较复杂,维护代码的时候往往会很难分清每个方法对应的功能,增加了代码维护成本。所以 vue3 舍弃了 Options API ,换用 Composition API。

Composition API 是 vue3 新增的,所以 vue2 没有。在 Composition API 中,根据代码逻辑功能来组织的,一个功能所定义的所有 API 都会放到一起,这样即使功能复杂,代码量增大,都可以一下子定位到某个功能的所有代码,代码维护方便。它的最大特点就是:高内聚,低耦合。

vue3 仍然支持 options API,但我们更推荐使用 Composition API。优劣比较:

更好的可编程性。

更优的代码组织。

更好的逻辑抽象能力。

对 tree-shaking 友好,代码也更容易压缩。

没有 this

watch 和 watchEffect 都是监听器,watchEffect 是一个副作用函数。它们之间的区别有:

watch 需要传入监听的数据源,而 watchEffect 可以自动手机数据源作为依赖。

watch 可以访问倒改变之前和之后的值,watchEffect 只能获取改变后的值。

watch 运行的时候不会立即执行,值改变后才会执行,而 watchEffect 运行后可立即执行。这一点可以通过 watch 的配置项 immediate 改变。

答:vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;
核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法,get set 方法。
简单地说,就是用这个方法来定义一个值。当调用时我们使用了它里面的get方法,当我们给这个属性赋值时,又用到了它里面的set方法;

Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。通俗说就是 Vue 实例从创建到销毁的过程,就是生命周期。
beforeCreate: vue元素的挂载元素el和数据都为undefined,还未初始化;
created:vue实例的数据对象data有了,el还没有;
beforeMount:vue实例的$el和data都初始化了,但是还挂载在之前的虚拟dom节点上,data.message还未替换;
mounted:vue实例挂载完成,data.message成功渲染。
更新前后:data变化时会触发beforeUpdate和updated方法;
销毁前后:beforeDestory和destoryed





beforeDestroy:
  • 在实例销毁之前调用。
  • 在这个阶段,实例仍然是完全可用的。
  • 允许开发者在组件销毁之前执行一些清理工作
讯享网
destroyed:
  • 在实例销毁之后调用。
  • 在这个阶段,实例的所有指令都已解绑,所有的事件监听器都已移除,所有的子组件实例也都被销毁。
  • 允许开发者在组件已经解绑定所有东西之后执行最终的清理工作
 

他的生命周期中有多个事件钩子,让我们控制整个vue实例的过程时更容易形成良好的逻辑。
生命周期钩子的一些使用方法:
beforeCreate:loading事件,在加载实例时触发。
created:初始化完成事件,异步请求。
mounted:挂载元素,获取dom节点
uptaded:对数据统一处理
beforeDestory:确认事件停止。
nextTick:更新数据后立即操作dom。






如果是把之前的 vue2 项目升级到 vue3 ,先卸载旧版本的 vue-cli,安装最新版本。安装完成之后,检查 vue 的版本。然后需要注意,把项目中 vue3 发生改变或被废弃的特性需要进行修改。如:

$children 被 vue3 移除,使用 $children 的需要替换为 $ref。

filters 被移除,更改为 computed 。

$destory 被移除,需要删除掉。

插槽的新变化。

Vuex 使用发生改变。

vue-router 使用发生改变等等。

在 vue2 中 v-for 的优先级更高,但是在 vue3 中优先级改变了。v-if 的优先级更高。

scrtpt setup 是 vue3 的语法糖,简化了组合式 API 的写法,并且运行性能更好。使用 script setup 语法糖的特点:

属性和方法无需返回,可以直接使用。

引入组件的时候,会自动注册,无需通过 components 手动注册。

使用 defineProps 接收父组件传递的值。

useAttrs 获取属性,useSlots 获取插槽,defineEmits 获取自定义事件。

默认不会对外暴露任何属性,如果有需要可使用 defineExpose 。

vue3支持webpack5的tree-shaking,因此现在所有api都需要导入后再使用:

ref:

常用:ref()、isRef()、unRef()、toRef()、toRefs()、shallowRef()

注:toRef()、toRefs()用在解构时仍希望数据为响应式时使用

reactive:

常用:reactive()、isReactive()、shallowReactive()、isProxy()、toRaw()
readonly:只读,不可修改
computed:

讯享网

watch:

 

watchEffect:立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数(写在watchEffect里的数据会被收集为其依赖,当这些依赖改变时才会触发watchEffect)

讯享网

Vue3中的Teleport 是控制渲染位置的新指令。它的作用是在DOM中移动一个组件的内容而不改变组件的父级。

Vue3中的Suspense是Vue3中新增的一个组件,它的作用是实现延迟加载和错误处理。在组件中加入Suspense,可以让异步组件可以渲染出加载状态,并且如果异步组件加载时出现错误,也能够处理这些错误。

响应式系统允许在状态发生变化时更新视图。Vue3中的响应式系统更新包括Proxy、Reflect和WeakMap等。

Vue3 Composition API是Vue3中的一个新特性,它的作用是将组件中的逻辑分解成可复用的可组合函数。通过使用Composition API,可以更好地组织代码和管理状态。

  1. Options API生命周期
  2. Composition API生命周期
  1. Composition API 更好的代码组织,更好的逻辑复用,更好的类型推到
  2. 小型项目,业务逻辑简单,用Options API
  3. 中大型项目,业务逻辑复杂的,用Composition API
  4. Composition API 是为了解决复杂业务逻辑而设计的
  5. 类似React Hooks
  1. ref
    1. 生成值类型的响应式数据
    2. 可用于模板和reactive
    3. 通过.value修改值
  2. toRef
    1. 针对一个响应式对象(reactive封装)的prop
    2. 创建一个ref,具有响应式
    3. 两者保持引用关系
  3. toRefs,避免模板中导出都是state
    1. 将响应式对象(reactive封装)转换成普通对象
    2. 对象的每个prop都是对应的ref
    3. 两者保持引用关系
  4. **使用方式
    1. 用reactive做对象的响应式,用ref做值类型的响应式
    2. setup中返回toRefs(state),或者toRef(state, ‘prop’)
    3. ref的变量命名都用xxxRef
    4. 合成函数返回响应式对象时,用toRefs
 
   
  1. setup和其他Composition API中都没有this
  2. 在Options API中仍然可以使用this
  3. Composition API中可以使用getCurrentInstance方法获取
  1. 前者setup(生命周期create)只会被调用一次,后者函数会被多次调用
  2. 前者无需useMemo,useCallback,因为setup只调用一次
  3. 前者无需考虑调用顺序,后者需要保证hooks的顺序一致

Vue3中的事件修饰符与Vue2基本相同,包括stop、prevent、capture和self等。

Vue3中使用 元素和 v-bind:is 属性来实现动态组件。例如, 。

Object.defineProperty 和 Proxy 的区别如下:

1.Proxy 可以直接监听对象而非属性;
2.Proxy 可以直接监听数组的变化;
3.Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的
4.Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty 只能遍历对象属性直接修改


Vue3中的指令包括v-if、v-for、v-bind、v-on、v-html、v-model、v-show、v-slot、v-text等。

vue2中 is是通过组件名称切换的,vue3中setup是通过组件实例切换的。直接把组件实例放到reactive中代理,vue会发出警告。告知我们可以通过shallowRef 或者 markRaw 跳过proxy 代理。对组件实例进行响应式代理毫无意义,且浪费性能

markRaw:标记一个对象,使其不能成为一个响应式对象。
toRaw:将响应式对象(由 reactive定义的响应式)转换为普通对象。
shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。
shallowReactive:只处理对象最外层属性的响应式(浅响应式)。


讯享网

Pinna是vue的最新状态管理工具, 它允许跨组件或页面共享状态,实现和Vuex一样的数据共享,用来替代vuex,并且更加简洁和易于使用。Pinia 支持 Vue 3,并且与 Vue 2 也有很好的兼容性。

安装依赖包
 
创建 Pinia Store
讯享网
在main.js中引入pinia
 
在需要使用的组件中引入store:
讯享网

由于vue2有局限性:

组件的逻辑膨胀导致组件的可读性变差;

无法跨组件重用代码;

vue2对TS的支持有限

composition API是根据逻辑相关性组织代码的,提高可读性和维护性

代码量少,更好的重用逻辑代码

没有引入新的语法,只是单纯函数

异常灵活

工具语法提示友好,因为是单纯函数所以很容易实现语法提示、自动补偿

更好的Typescript支持

在复杂功能组件中可以实现根据特性组织代码,代码内聚性强

组件间代码复用

setup函数接收两个参数,分别是 props 和 context。

1、props:值为对象,包含: 组件外部传递过来。切组件内部声明接收了的属性。需要注意的是,Vue3中的 props 是只读的,即在setup 函数中不能修改 props 的值。如果需要修改传递过来的数据,可以使用响应式对象或ref。

2、context:上下文对象。

attrs:值为对象,包含组件外部传递过来,但没有在props配置中声明的属性。相当于this.$attrs

slots:收到的插槽内容,相当于this.$slots

emit:分发自定义事件的函数,相当于this.$emit

1、provide和inject是一对新的API,用于在父组件中提供数据,然后在子组件中注入数据。

2、provide:是一个对象,或者是一个返回对象的函数。里面呢就包含要给子孙后代的东西,也就是属性和属性值。

3、inject:一个字符串数组,或者是一个对象。属性值可以是一个对象,包含from和default默认值。

 

1、shallowRef:只处理基本数据类型的响应式

2、shallowReactive:只处理对象最外层属性的响应式(浅响应式)

3、浅层作用的响应式数据处理:只处理第一层对象的数据,再往下嵌套的数据,操作数据是不起作用的

4、shallowReative与shallowRef在某些特殊的应用场景下,是可以提升性能的,前者针对对象,用于浅层作用的响应式数据处理,而后者只处理基本数据类型的响应式,不进行对象的响应式处理。

readonly与shallowReadonly都是让响应式数据只具备读的能力,后者是浅层次的只读,也就是只对数据对象第一层起作用,深层次的嵌套,当时用shallowReadonl()处理时,深层次数据支持被修改

1、readonly: 让一个响应式数据变为只读的 (深只读),让一个响应式数据变为只读的,接收一个响应式数据,经过readonly加工处理一下,那么新赋值的数据都不允许修改

2、接受一个对象 (不论是响应式还是普通的) 或是一个 ref,返回一个原值的只读代理

3、shallowReadonly: 让一个响应式数据变为只读的 (浅只读),接收一个响应式数据,经过shallowreadonly的处理,变成一个只读的,只考虑对象的第一层数据,不可以修改,但是第一层嵌套里的深层数据却支持修改

4、让一个响应式数据变为只读能力(浅只读).

1、父传子:

1、在父组件的子组件标签上通过:传到子组件的数据名=‘需要传递的数据’

2、子组件中通过props进行接收并在模板中使用

2、子传父:

1、子组件触发事件通过setup函数的第二个参数,context.emit来实现子传父

  1. 简单来说, ref通常用来定义数据, reactive用来定义类型数据

注: ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象。

  1. 使用方面: ref 操作数据取值,template模板中不需要。

解构赋值会使reactive丢失响应性, 而{ref(1), ref(2)}不会

  1. 原理角度:

ref通过Object.defineProperty()的get与set来实现响应式(数据劫持)。

reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。

isRef: 检查一个值是否为一个 ref 对象

isReactive: 检查一个对象是否是由 reactive 创建的响应式代理

isReadonly: 检查一个对象是否是由 readonly 创建的只读代理

isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理

作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性。

语法:const name = toRef(person,‘name’)

应用: 要将响应式对象中的某个属性单独提供给外部使用时。

扩展:toRefs 与toRef功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)

在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中

好处: 减少标签层级, 减小内存占用

讯享网

使用步骤:

异步引入组件

 

使用Suspense包裹组件,并配置好default 与 fallback

讯享网

  • 今天就写到这里啦~
  • 小伙伴们,( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ我们明天再见啦
  • 大家要天天开心哦

在这里插入图片描述

欢迎路过的小哥哥小姐姐们提出更好的意见哇


小讯
上一篇 2025-04-19 13:36
下一篇 2025-05-07 08:27

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/183262.html