Vue2023 面试归纳及复习

news2024/11/27 13:37:48

1. Vue 3中的Composition API(Hooks)是什么?它与Options API有何不同?`


答:Composition API是Vue 3中引入的一种新的API风格,

用于组织和重用组件逻辑。它与Options API相比,

提供了更灵活和可组合的方式来编写组件逻辑。

Composition API使用函数式的API,将相关的逻辑组合在一起,而不是将逻辑分散在不同的选项中。

composition API的好处(带来了什么):

  1. 更好的代码组织(相关逻辑代码可以集中放在一块,而不是分散存在);
  2. 更好的逻辑复用;我们可以将一些常用的逻辑封装成自定义的函数,然后在多个组件中进行重用
  3. 更好的类型推导(比如:optons api中,方法被定义在methods中,但是调用时直接使用this来调用,不符合js语法规范,也不利于我们使用语法的方式来推导类型及属性);
  4. 适用于大型的复杂项目;

不要说setup  跟 composition没啥关系 

1 Composition API 的出现解决了这个问题。它允许我们通过函数的方式组织组件的逻辑,将相关的代码放在一起,使得代码更加清晰、可读性更高。

2. 更好的类型推导和编辑器支持
Composition API 的另一个优势是更好的类型推导和编辑器支持。由于 Composition API 使用了函数的方式来组织代码,编辑器可以更准确地推断变量的类型和提供代码补全。

在 Vue 3 中,通过使用 TypeScript,我们可以为 Composition API 提供类型声明,使得编辑器能够提供更好的代码提示和错误检查。

3. 更好的逻辑复用
Composition API 使得逻辑复用变得更加容易。我们可以将一些常用的逻辑封装成自定义的函数,然后在多个组件中进行重用。

在 Vue 2 中,我们使用 Options API 来编写组件。Options API 是一种基于选项的编程模式,将组件的各种选项(如数据、计算属性、方法等)放在一个对象中。这种方式在小型项目中运作良好,但随着项目规模的增长,组件变得越来越复杂,代码逻辑难以维护和重用。

composition API和Options API如何选择?

  1. 不建议共用,容易引起混乱;

  2. 小型项目、业务逻辑简单用Options AP,因为使用起来简单,门槛更低;

  3. 中大型项目,逻辑复杂,使用composition API

Vue 3 中的 Composition API 是什么?它的优势是什么?_程序员徐师兄的博客-CSDN博客

传统 Options API 中,新增或者修改一个需求,需要分别在 datamethodscomputed,… 里进行修改 。

Composition API 的优势

可以更加优雅的组织我们的代码,函数。能够让相关功能的代码更加有序的组织在一起。

  • 能够将代码按照功能进行封装,降低开发成本与后期维护成本,且让setup中的逻辑更清晰易读。
  • 能够方便的实现代码逻辑复用。

2    Options API 语法格式 

atamethodscomputed

Vue2采用选项式API(Options API)格式,该格式会导致对相同数据进行操作使用的代码被分割到不同属性内,很不利于代码的阅读。

<template>
    <h1>{{helloText}}</h1>
</template>
<script>
     export default{
        props:['msg'],
        data(){
            return {
                count:0, //逻辑1的数据
                name:'HelloWorld' //逻辑2的数据
            }
        },
        methods:{
            onAdd(){  //逻辑1的方法
                this.count++;
            },
            getCount(){ //逻辑2的方法
                this.count=Math.floor(Math.random()*100);
            }
        },
        computed:{
            helloText(){  //逻辑2的计算属性
               return this.msg+' '+this.name;
            }
        },
        watch:{     
            count(){  //逻辑1的watch
                console.log('count 变了');
            }
        },
        mounted(){
            this.getCount() //逻辑1的初始化操作
        }
     }
</script>
<style scoped>
  a{
    color:#42b983
  }
</style>

Vue:对比于 Options API,为什么 Composition API 很香?_shangdong2023的博客-CSDN博客

3 setup 语法糖

<script setup>是在单文件组件中使用Composition API的编译时语法糖。相比于普通的<script>语法,它具有更多优势

  1. 不用写setup函数
  2. 组件只需要引入不需要注册
  3. 属性和方法也不需要再返回,可以直接在template模板中使用。

在 Vue 3 当中我自己感觉最鲜明的变化就是 Vue 3 中引入了组合式 Api (composition API)
但是使用 Vue3 组合式 API 的时候感觉整个过程比较繁琐

  • 在 setup () 当中定义 ⇒ setup() 中 return ⇒ 模板中使用

如果需要定义一个方法的话,模板中使用这个方法的时候,需要在 setup 函数中将它返回,模板中需要用到的大量的方法和属性都需要一 一返回 , 这个过程有点难受,时不时的就会漏掉返回这一步导致变量未定义或者 xx not a function 的错误

<script>
import {defineComponent , reactive, ref} from 'vue'
export default defineComponent({
  setup(){
    // 基本类型变量
    const name = ref("你好")
    const age = ref(2023)
    // 引用类型变量
    const book = reactive({name:"月亮",age:"1919"})

    // 将变量返回
    return{
      name,
      age,
      book
    }
  }
})
</script>

因为 setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 setup 函数中编写。

可以通过在生命周期钩子前面加上 “on” 来访问组件的生命周期钩子。官网:生命周期钩子

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

obeforeCreate===>setup()
created =======> setup()
beforeMount ===> onBeforeMount
mounted =======> onMounted
beforeUpdate ===> onBeforeUpdate
updated =======>onUpdated
beforeUnmount ==> onBeforeUnmount
unmounted =====> onUnmounted
 

 4  Vue3的生命周期

组合式API形式使用
Vue3.0 中可以继续使用 Vue2.x中 的生命周期钩子,但有有两个被更名:
。beforeDestroy改名为beforeUnmount
。destroyed改名为unmounted

vue2                  -> vue3
beforeCreate     -> 使用 setup()     创建
created               -> 使用 setup()
beforeMount       -> onBeforeMount    挂载
mounted             -> onMounted

beforeUpdate     -> onBeforeUpdate  更新
updated              -> onUpdated
beforeDestroy      -> onBeforeUnmount   卸载
destroyed              -> onUnmounted
errorCaptured       -> onErrorCaptured 

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

obeforeCreate===>setup()
created =======> setup()
beforeMount ===> onBeforeMount
mounted =======> onMounted
beforeUpdate ===> onBeforeUpdate
updated =======>onUpdated
beforeUnmount ==> onBeforeUnmount
unmounted =====> onUnmounted

①onBeforeMount:在挂载开始之前被调用:相关的 render 函数首次被调用。

②onMounted: 组件挂载时调用

③onBeforeUpdate:  数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。

④onUpdated

由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。

⑤onBeforeUnmount
在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的。

⑥onUnmounted
卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载。

⑦onActivated 【了解】
被 keep-alive 缓存的组件激活时调用。

⑧onDeactivated 【了解】
被 keep-alive 缓存的组件停用时调用。

⑨onErrorCaptured【了解】
当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回
false 以阻止该错误继续向上传播。

 Vue3 调试钩子:

onRenderTracked

跟踪虚拟 DOM 重新渲染时调用。钩子接收 debugger event 作为参数。此事件告诉你哪个操作跟踪了组件以及该操作的目标对象和键。

renderTracked

当虚拟 DOM 重新渲染为 triggered.Similarly 为renderTracked,接收 debugger event 作为参数。此事件告诉你是什么操作触发了重新渲染,以及该操作的目标对象和键。

5. 请解释一下Vue 3中的Teleport(传送)和Suspense(异步组件)是什么,以及它们的作用。

答:Teleport是Vue 3中引入的一个新组件,用于将组件的内容渲染到DOM树中的指定位置。

它可以在组件的模板中指定一个目标,使得组件的内容可以被渲染到目标的位置,而不是直接渲染在组件所在的位置。

Suspense是Vue 3中引入的另一个新组件,用于处理异步组件的加载过程。通过在Suspense组件中包裹异步组件,并提供一个fallback选项,可以在异步组件加载过程中展示一个占位符,直到异步组件加载完成后才显示真正的内容。

<template>
  <div class="main">
    <Suspense>
      <template #default>
        <A />
      </template>
      <template #fallback>
        <h3>加载中.....</h3>
      </template>
    </Suspense>
  </div>
</template>
<script setup lang="ts">
import A from "./A.vue";
</script>
<style scoped>
.main {
  width: 100%;
  height: 100%;
}
</style>

<Suspense> 是一个内置组件,用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态。

Vue3 新特性 内置组件 <Teleport>_织_网的博客-CSDN博客

Vue3中 内置组件 Teleport 详解_vue3 teleport_明天也要努力的博客-CSDN博客

Suspense组件_会说法语的猪的博客-CSDN博客

6. Vue 3中的响应式系统是如何工作的?请解释一下Reactive和Ref的区别。

答:Vue 3中的响应式系统使用Proxy对象来追踪数据的变化。当数据被访问时,Proxy会收集依赖关系,并在数据变化时触发更新。


Reactive函数是Vue 3中提供的一个全局函数,用于将一个对象转换为响应式对象。它接收一个普通对象作为参数,并返回一个响应式代理对象,可以通过该代理对象访问和修改原始对象的属性。

Ref是Vue 3中提供的一个函数,用于创建一个包装器对象,将一个普通的JavaScript值转换为响应式对象。Ref对象可以通过.value属性访问和修改其包装的值。

7. 请描述一下Vue 3中的虚拟DOM(Virtual DOM)和Diff算法的工作原理。

答:Vue 3中的虚拟DOM是一个内存中的表示,类似于真实DOM结构的JavaScript对象。当数据发生变化时,Vue 3会通过对比新旧虚拟DOM的差异,找出需要更新的部分,然后仅更新那些需要变化的部分,而不是直接操作真实的DOM。
Diff算法是用于比较新旧虚拟DOM树的算法。它会逐层对比两棵树的节点,找出差异,并生成一系列需要进行更新的操作。Diff算法通过一些优化策略,如同级比较、Key的使用等,来尽量减少更新的操作次数,提高性能。

8  Vue 3中的响应式数据如何实现异步更新?请解释一下setup()函数中的异步处理。

Vue 3中的响应式数据可以通过reactive()函数或ref()函数进行定义。

当响应式数据发生变化时,Vue 3会将更新操作推迟到下一个事件循环中执行,以保证多个更新操作的批处理。
在setup()函数中,可以返回一个Promise对象来实现异步处理。当Promise对象解析时,组件会重新渲染,以反映最新的数据状态。

 9 Vue 3中的动态组件是什么?如何在Vue 3中使用动态组件?

答:动态组件是指在运行时根据条件来动态选择渲染不同的组件。在Vue 3中,可以使用元素和:is属性来实现动态组件的渲染。
在模板中使用元素,并将要渲染的组件的名称或组件对象赋给:is属性。根据条件的变化,Vue 3会动态地选择渲染不同的组件。

10  请解释一下Vue 3中的 静态提升和Patch Flag  (补丁标记) 的优化策略。

答:

静态提升是Vue 3中的一项优化策略,用于减少渲染时的虚拟DOM节点创建和比较的开销。

在编译过程中,Vue 3会分析模板中的静态内容,并将其提升为一个单独的静态节点,减少对比的复杂性。

 在Vue2中,每次更新diff,都是全量对比,Vue3则只对比带有标记的,这样大大减少了非动态内容的对比消耗


Patch Flag是Vue 3中的一种标记,用于标识虚拟DOM节点的属性和状态变化。通过在虚拟DOM节点上设置Patch Flag,Vue 3可以跳过对比不必要的属性和状态,以提高性能。
 

在Vue3中有哪些静态标记?  

export const enum PatchFlags {
  
  TEXT = 1,// 1 动态的文本节点
  CLASS = 1 << 1,  // 2 动态的 class
  STYLE = 1 << 2,  // 4 动态的 style
  PROPS = 1 << 3,  // 8 动态属性,不包括类名和样式
  FULL_PROPS = 1 << 4,  // 16 动态 key,当 key 变化时需要完整的 diff 算法做比较
  HYDRATE_EVENTS = 1 << 5,  // 32 表示带有事件监听器的节点
  STABLE_FRAGMENT = 1 << 6,   // 64 一个不会改变子节点顺序的 Fragment
  KEYED_FRAGMENT = 1 << 7, // 128 带有 key 属性的 Fragment
  UNKEYED_FRAGMENT = 1 << 8, // 256 子节点没有 key 的 Fragment
  NEED_PATCH = 1 << 9,   // 512  表示只需要non-props修补的元素 (non-props不知道怎么翻才恰当~)
  DYNAMIC_SLOTS = 1 << 10,  // 1024 动态的solt
  DEV_ROOT_FRAGMENT = 1 << 11, //2048 表示仅因为用户在模板的根级别放置注释而创建的片段。 这是一个仅用于开发的标志,因为注释在生产中被剥离。
 
  //以下两个是特殊标记
  HOISTED = -1,  // 表示已提升的静态vnode,更新时调过整个子树
  BAIL = -2 // 指示差异算法应该退出优化模式
}

Vue3的编译优化:Block树和PatchFlags_姑老爷呀的博客-CSDN博客

简略介绍Vue3之新特性_vue3 虚拟标签_前端布道人的博客-CSDN博客

11. Vue 3中的Fragment(片段)是什么?它有什么作用?

答:Fragment是Vue 3中引入的一个组件,用于包裹一组连续的节点,并且不会在渲染结果中引入额外的父节点。它可以用来替代使用等标签包裹多个节点的情况,以减少生成的DOM层级。
使用Fragment可以改善渲染性能和DOM结构的简洁性,特别是当需要在循环或条件语句中渲染多个节点时。

在 Vue 3 中,要使用 Fragments,我们可以使用特殊的语法来表示一个 Fragment。这个特殊语法是使用尖括号和 v-if 指令来实现的。

下面是一个示例代码,展示了如何使用 Fragments:

<template>
  <>
    <h1>标题</h1>
    <p>正文内容</p>
    <button>点击我</button>
  </>
</template>

在上面的代码中,我们使用 <> 和 </> 将 <h1>、<p> 和 <button> 包裹起来,形成了一个 Fragment。这样,我们就可以直接将多个子元素组合在一起,而无需引入额外的包裹元素。

需要注意的是,在使用 Fragments 时,我们并不需要指定 key 属性。Vue 3 会自动处理 Fragments 中子元素的渲染和更新,而无需我们手动管理。
 

Fragments 的优势
使用 Fragments 有以下几个优势:

1. 简洁性
Fragments 允许我们在不引入多余包裹元素的情况下,组合和渲染多个子元素。这样可以减少 DOM 结构的嵌套层级,使代码更加简洁易读。

2. 更好的性能
相对于使用包裹元素的方式,Fragments 可以减少不必要的 DOM 元素,从而提高渲染性能。因为在 Fragments 中,不会创建额外的 DOM 节点。

3. 更好的样式控制
使用 Fragments 可以避免引入额外的包裹元素,从而减少对样式的影响。特别是在使用 CSS 布局库或者进行样式复用时,Fragments 可以提供更好的样式控制。

总结
Vue 3 中的 Fragments 是一个非常有用的特性,它允许我们更简洁地组合和渲染多个子元素,而无需引入额外的包裹元素。通过使用 <> 和 </> 将多个子元素包裹起来,我们可以享受到简洁性、更好的性能和更好的样式控制。使用 Fragments 可以避免引入额外的包裹元素,从而减少对样式的影响。特别是在使用 CSS 布局库或者进行样式复用时,Fragments 可以提供更好的样式控制。

12 请解释一下Vue 3中的全局API和实例API的区别。

答:Vue 3中的全局API是指可以在任何组件中直接访问的API,如createApp、directive、

vue2中:有许多的全局API,如:Vue.directive、Vue.component、Vue.config、Vue.mixin等
vue3中:提供的是实例API,通过createApp创建vue实例,原来在Vue原型上的API都被挂载到了vue实例上,如:app.directive、app.component、app.config、app.mixin等

全局API:

1. createApp()  创建一个应用实例。

2. createSSRApp()  以SSR创建一个应用实例,和createApp()用法一样。

3. app.mount(msg)   将一个应用实例挂载到某个元素上。

4. app.unmount()  卸载一个已经挂载的应用实例,会触发这个实例内所有组件的卸载生命周期函数

5. app.provide(key, value) 注入  用来提供一个值,可以让应用所有的后代组件都可以使用。

6. app.component()   定义一个全局组件,或返回一个组件。

7. app.directive()

如果同时传递一个名字和一个指令定义,则会注册一个全局指令;如果只传递一个名字,会返回用该名字注册的指令 (如果存在的话)。

8. app.use()

安装一个插件

第一个参数应是插件本身,第二个参数可选是要传递给插件的选项。

9. app.version

版本号,查询该应用的版本号。可以在插件中使用,比较这个插件满足那个版本才能使用。

实例API :

在Vue3中,使用vue中的createApp方法可以创建一个Vue应用实例。

1、component方法:

注册或检索全局组件。注册还会使用给定的 name 参数自动设置组件的 name。

2、config属性
一个包含应用配置的对象。

3、directive方法
注册或检索全局指令。

4、mount方法
所提供 DOM 元素的 innerHTML 将被替换为应用根组件的模板渲染结果。

5、provide方法
设置一个可以被注入到应用范围内所有组件中的值。组件应该使用 inject 来接收 provide 的值。

6、unmount方法
卸载应用实例的根组件

7、use
安装 Vue.js 插件。如果插件是一个对象,则它必须暴露一个 install 方法。如果插件本身是一个函数,则它将被视为 install 方法。

Vue 实例之全局API,实例属性,全局配置,组件进阶_大可爱学编程ฅ´ω`ฅ的博客-CSDN博客

【Vue3】Vue实例API介绍_vue3获取vue实例_h沐的博客-CSDN博客

13. Vue3和Vue2最大区别。

重要的几个区别: Vue响应式的底层实现不同     语法API不同   

 生命周期     this     Typescript支持

 不太重要的 :  v-if和v-for的优先级    .sync修饰符   key在template和v-if上的使用

一、Vue响应式的底层实现不同

二、生命周期有一定的区别

三、支持碎片化,可以有多个根节点

Vue3 支持多个根节点,也就是 fragment。即以下多根节点的写法是被允许的

四,模板指令

在vue2中,v-for 优先级高于 v-if;

在vue3 中,v-if 优先级高于v-for;

五、语法API不同

Vue2:选项式API,面向对象编程

Vue3:选项式API/组合式API,面向函数编程;

没有this,处处皆函数

3、全局API
vue2中:有许多的全局API,如:Vue.directive、Vue.component、Vue.config、Vue.mixin等
vue3中:提供的是实例API,通过createApp创建vue实例,原来在Vue原型上的API都被挂载到了vue实例上,如:app.directive、app.component、app.config、app.mixin等

1、v-if和v-for的优先级
在vue2中:当v-if和v-for同时使用时,v-for的优先级高于v-if(因此我们通常需要计算属性先对数据进行加工处理,以达到性能优化的目的)
在vue3中:当v-if和v-for同时使用时,v-if的优先级高于v-for


2、.sync修饰符
vue2中:由于vue中是单向数据流,父子组件在传值时想要实现v-model的效果就要用到.sync修饰符来实现“双向绑定”
vue3中:对v-model进行了改造,不再需要 .sync 修饰符即可达到数据双向绑定的效果。在vue3中支持多个 v-model属性,默认使用 modelValue 作为 prop,update:modelValue作为事件,当多个v-model绑定时,书写为例:v-model:title="title",此时 title 作为prop,update:title 作为事件

4、Vue.prototype 替换为 config.globalProperties
vue2中:绑定全局的变量、方法等:Vue.prototype.$ajax = xxxx
vue3中:const app = createApp({}); app.config.globalProperties.$ajax = xxxx


5、生命周期
vue2    vue3
beforeCreate


6、key在template和v-if上的使用
vue2中:在使用v-if、vi-else、v-else-if时,为了保证dom节点渲染的正确性,通常需要在对应的节点添加不同的key,以确保vue在进行虚拟dom对比时是准确的;vue2中template在v-for循环时是不能设置key的,否则会产生警告(需要给子节点设置key)。
vue3中:在使用v-if、vi-else、v-else-if时,不用提供唯一的key对dom节点进行区分,因为vue内部会自动生成唯一的key,如果你提供了key,那你就要保证它的唯一性;vue3中template在v-for循环时,key应该设置在template标签上
7、$listeners被移除
vue2中:使用$attrs访问传递给组件的属性,使用$listeners访问传递给组件的事件(需要结合inheritAttrs:false)。
vue3中:虚拟dom中,事件监听器仅仅是以on为前缀的属性


8、this
vue2中:无时无刻都要使用this
vue3中:因为setup函数的存在,所有的props、data等都不需要用this进行访问(vue3对vue2绝大多数是兼容的,如果你用了vue2相关的东西,那你还是需要像vue2一样书写)
9、typescript支持
vue2中:默认是不支持typescript的。
vue3中:支持使用typescript,使用typescript在构建大型项目时,能够很好的提高项目开发的质量。
 

新特性 区别 

Vue3和Vue2的区别_vue2和vue3区别_你吃香蕉吗?的博客-CSDN博客

14 Vue2.0 的响应式原理

原理:通过数据劫持 defineProperty + 发布订阅者模式,当 vue 实例初始化后 observer 会针对实例中的 data 中的每一个属性进行劫持

使用的Object.defineProperty()重新定义对象,给data的每个属性都添加了getter和setter方法。这时候会为对象的每个属性创建一个Dep实例  (依赖)。Dep实例可以订阅和通知相关的Watcher实例。,  这一步叫  数据劫持  或者 依赖收集

在数据发生更新后调用 set 时会通知发布者 notify 通知对应的订阅者做出数据更新,同时将新的数据根性到视图上显示。 这一步叫 派发更新

Vue2的响应式原理通过使用Object.defineProperty方法来实现属性的劫持和侦听,同时使用Dep和Watcher实例来建立属性和依赖之间的关系,并进行更新通知。同时,为了解决对象属性添加和删除的问题,Vue提供了全局的Vue.set和Vue.delete方法,以及实例的vm.$set和vm.$delete方法。

缺陷:只能够监听初始化实例中的 data 数据,动态添加值不能响应,要使用对应的 Vue.set()。

解释:

  1. 在创建 Observer 实例的同时还会创建 Dep 实例,用于保存依赖项。因此每个数据都有 Observer 的实例,每个 Observer 实例中又都有一个 Dep 的实例。
  2. 当 Vue 解析到当解析到模板字符串 {{ }} 时中数据时,就会去创建 Watcher 实例,在 constructor 时会调用自身的 get 方法,该方法不仅将当前的 Watcher 实例赋值给了 Dep.target(表示此时处于依赖收集阶段),还让这个新实例去读取一下 {{ }} 中的数据,一旦读取,就会触发这个数据的 getter 方法。因为此时正在进行收集依赖,Dep.target 一定是为 true 的,于是顺利地把当前的这个 Watcher 实例记录到了 dep 中的 subs 数组里。再然后将 Dep.target 的值重新赋值为 null,表示退出依赖收集阶段

1 在initState()方法里会对组件的props, methods, data,computed, watch等进行编译初始化=>

2 initData()会先获取组件内部的data数据,然后判断data里的数据和props,或者和methods里的名称重复,则抛出错误提示,然后就会去监听data,执行observe方法=>

3   Observer()  =>   defineReactive, dependArray =>  defineProperty()   =>   Observer()    递归

使用的Object.defineProperty()重新定义对象,给data的每个属性都添加了getter和setter方法。

在get的时候会调用dep.depend;如果是数组,则调用dependArray(对数组里的每个元素进行递归调用dep.depend);
在set的时候会先判断数据是否更新,未更新不做操作,更新则observe(),且dep.notify()

总结:

在Vue2中,响应式原理是通过使用Object.defineProperty方法来实现的。当一个对象被传入Vue的observe函数中时,Vue会为对象的每个属性创建一个Dep实例。Dep实例可以订阅和通知相关的Watcher实例。

当一个属性被访问时,Watcher实例会将自己添加到该属性的Dep实例的订阅列表中。当该属性的值发生变化时,Dep实例会遍历订阅列表,通知所有相关的Watcher实例进行更新。

然而,Vue无法检测到对象属性的添加和删除。为了解决这个问题,Vue提供了全局的Vue.set方法或实例的vm.$set方法来添加属性,使用Vue.delete方法或实例的vm.$delete方法来删除属性。对于数组的变动,Vue无法检测到利用索引设置数组,但可以使用Vue.set方法或实例的vm.$set方法。此外,Vue也无法检测直接修改数组长度,但可以使用splice方法来实现。

总结起来,Vue2的响应式原理通过使用Object.defineProperty方法来实现属性的劫持和侦听,同时使用Dep和Watcher实例来建立属性和依赖之间的关系,并进行更新通知。同时,为了解决对象属性添加和删除的问题,Vue提供了全局的Vue.set和Vue.delete方法,以及实例的vm.$set和vm.$delete方法。

15 Vue3.0 的响应式原理

总结来说就是:Vue3使用了Proxy来劫持数据,通过代理对象拦截属性的读取和赋值操作。当对属性进行赋值时,会触发代理对象的set拦截函数执行,从而实现对属性的监听和更新。

  • 在Vue3中,使用reactive函数可以将一个普通的JavaScript对象转换为响应式对象。该函数使用Proxy对对象的属性进行劫持,使得修改属性时可以触发相应的更新操作。
  • 此外,Vue3还引入了effect函数,用于创建副作用函数,即在响应式对象变化时执行的函数。effect函数接受一个用户自定义的fn函数和options选项,可以用于实现具体的业务逻辑。
  • 总结来说,Vue3的响应式原理通过Proxy的劫持数据实现属性的监听和更新,同时配合reactive和effect函数提供了更强大的响应式能力。这样可以实现组件的自动更新,提升开发效率和用户体验。

我们总结一下整个数据绑定建立响应式大致分为三个阶段

1 初始化阶段: 初始化阶段通过组件初始化方法形成对应的proxy对象,然后形成一个负责渲染的effect。

2 get依赖收集阶段:通过解析template,替换真实data属性,来触发get,然后通过stack方法,通过proxy对象和key形成对应的deps,将负责渲染的effect存入deps。(这个过程还有其他的effect,比如watchEffect存入deps中 )。

3 set派发更新阶段:当我们 this[key] = value 改变属性的时候,首先通过trigger方法,通过proxy对象和key找到对应的deps,然后给deps分类分成computedRunners和effect,然后依次执行,如果需要调度的,直接放入调度。


 

16   Vue3.0中的响应式原理是什么?vue2的响应式原理是什么?

(1)vue2.x版本响应式基于ES5的Object.defineProperty实现

(2)Vue3.x版本响应式基于ES6(es2015)的Proxy实现

总结

在vue2中利用的是原生js下边的Object.defineProperty()进行数据劫持,在通过里面的getter和setter方法,进行查看和数据的修改,通过发布、订阅者模式进行数据与视图的响应式。vue2是对对象的所有属性进行递归, 让每个对象的每个属性都调用Object.defineProperty()为止。

  • vue2使用Object.defineProperty()实现响应式原理,而vue3使用Proxy()实现。
  • 虽然vue2,vue3面对对象嵌套,都需要递归,但vue2是对对象的所有属性进行递归,
  • vue3是按需递归,如果没有使用到内部对象的属性,就不需要递归,性能更好。
  • vue2中,对象不存在的属性是不能被拦截的。而vue3可以。
  • vue2对数组的实现是重写数组的所有方法,并改变,vue2中,数组的原型来实现,而Proxy则可以轻松实现。而且vue2中改变数组的长度是无效的,无法做到响应式,但vue3可以。

Vue3.0的相应式原理:利用Proxy劫持对象,访问对象的时候会触发get方法,此时会进行依赖的收集;当修改对象数据的时候会触发set方法,此时会派发依赖,即调用组件的副作用渲染函数(其实不限于), 这样组件就能重新渲染,DOM更新。

17  有哪些vue3响应性判断函数?

isRef
判断一个值是否为一个 ref 对象
isReactive
判断一个对象是否是由 reactive创建的响应式代理
isReadonly
判断一个对象是否是由 readonly 创建的只读代理
isProxy
判断一个对象是否是由 reactive 或 readonly 创建的代理
 

18 介绍一下   ref    reactive       toRef    toRefs  函数 

ref

ref是Vue3提供的一种用于包装基本数据类型的响应式对象的实现方式。

在Vue3中,使用ref可以将基本数据类型(如字符串、数字、布尔值等)包装为响应式对象。当这些基本数据类型的值发生变化时,Vue3会自动更新视图中相应的内容。

需要注意的是,在使用ref包装基本数据类型时,我们需要通过.value来访问这个值。这是因为ref返回的是一个包含.value属性的响应式对象,而不是一个基本数据类型的值。

reactive

reactive是Vue3提供的一种用于包装对象的响应式对象的实现方式。在Vue3中,使用reactive可以将对象包装为一个响应式对象。当这个对象的属性发生变化时,Vue3会自动更新视图中相应的内容。

和ref不同的是,reactive可以深层代理数据

reactive为传入的数据包装ref,生成value,利用Proxy代理检测数据变化。

注意::一般引用数据类型添加响应式使用reactive, 基本数据类型使用ref

vue3响应式数据的相关函数_let data = ref()_MiMenge的博客-CSDN博客

ref和reactive的区别

在使用ref和reactive时,需要注意它们之间的区别。ref适用于包装基本数据类型,而reactive适用于包装对象。此外,ref返回的是一个包含.value属性的响应式对象,而reactive返回的是一个包装后的响应式对象。

toref   函数

创建一个ref对象,这个响应式对象的value引用了接收的对象的某个响应式属性,且与源数据保持引用关系

let data = { num: 0, o: ["1", 2], },

let dynamicProp = toRef(refData, "o");

 toRefs函数

和toRef功能差不多,只不过toRefs可以创建多个ref对象
因为当有多个响应式对象需要单独提取的时候,toRef就显得过于复杂了,使用toRefs可以简化这个过程

let { o, num, job } = toRefs(refData);

在某些情况下,我们希望将一个响应式对象的属性单独作为响应式属性使用,而不是将整个对象作为一个响应式数据使用。这时就可以使用 toRefs 函数。

Vue 3 中的 toRefs 函数是一个非常有用的工具,它可以将一个响应式对象转换为一组响应式属性。这个函数可以用于将父组件中的响应式对象传递给子组件,并在子组件中以单独的响应式属性的形式使用它们。

shallowRef

特殊的ref,只处理基本数据类型的响应式,无法为引用数据类型添加响应式

shallowReactive

只为对象的第一层属性添加响应式

triggerRef

ref生成的数据强制在页面更新页面

前面在使用shallowRef添加响应对象时,数据不能更新到页面,使用triggerRef便可以强制更新

 readony

让一个响应式数据变为深只读

shallowReadony

让一个响应式数据变为浅只读

toRaw

将响应式数据变更为非响应式数据(基础数据)

11 markRaw

将响应式数据永久变更为非响应式数据

12 customRef

自定义ref, 通过基础ref配置满足自定义要求的ref

vue3响应式数据的相关函数_let data = ref()_MiMenge的博客-CSDN博客

【Vue3响应式】ref、reactive,以及toRefs 函数_m0_71975585的博客-CSDN博客

19  setup函数怎么用?

1、setup函数在beforeCreate和created之前执行

2、在setup函数中定义的变量和方法需要return出去,不然无法在模板中使用

3、setup函数是Composition API的入口。

setup函数里面是没有this对象的,使用它的话会报 undefined。

setup函数那么它讲会有两个参数分别是  props  和  context

 
export default {
  props: {
    item: String
  },
  setup(props,context) { //   setup(props,{ emit } ) 解构赋值
    console.log(props.item) // 这个可以访问到props里面的值
    console.log(context.emit) // 这个可拿到emit方法
  }
}

props 是响应式的,当传入新的 props 时,它将被更新。但是,因为 props 是响应式的,你不能使用 ES6 解构,它会消除 prop 的响应性。

setup第二参数是 Context 

context 是一个普通 Js 对象,

context 是一个普通的 JavaScript 对象,也就是说,它不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构。

export default {
  setup(props, { attrs, slots, emit, expose }) {
    ...
  }
}

20  watch 和 watchEffect 区别

  • watch- 显式指定依赖源,依赖源更新时执行回调函数

  • watchEffect - 自动收集依赖源,依赖源更新时重新执行自身

1.watch是惰性执行,也就是只有监听的值发生变化才会执行,但watchEffect不同,每次代码加载watchEffect都会执行。

注:(忽略watch第三个参数的配置,如果修改配置项,也可以实现立即执行)。

2.watch需要传递监听的对象,watchEffect不需要。   

3.watch只能监听响应式数据:ref定义的属性和reactive定义的对象,如果直接监听reactive定义对象中的属性是不允许的 (会报警告),除非使用函数转换一下,既要指明监视的属性,也要指明监视的回调。

  

4.watchEffect如果监听reactive定义的对象是不起作用的 ,只能监听对象中的属性。
 

Vue3 中 watch 与 watchEffect 有什么区别?_vue3 watcheffect和watch区别_琉璃℡初雪的博客-CSDN博客

21  什么是SSR(服务端渲染),原理是什么? 好处有哪些?

服务端渲染

服务端渲染 SSR (Server-Side Rendering),是指在服务端完成页面的 html 拼接处理, 然后再发送给浏览器,将不具有交互能力的 html 结构绑定事件和状态,在客户端展示为具有完整交互能力的应用程序。

适用场景

以下两种情况 SSR 可以提供很好的场景支持

  • 需更好的支持 SEO

    优势在于同步。搜索引擎爬虫是不会等待异步请求数据结束后再抓取信息的,如果 SEO 对应用程序至关重要,但你的页面又是异步请求数据,那 SSR 可以帮助你很好的解决这个问题。

  • 需更快的到达时间

    优势在于慢网络和运行缓慢的设备场景。传统 SPA 需完整的 JS 下载完成才可执行,而SSR 服务器渲染标记在服务端渲染 html 后即可显示,用户会更快的看到首屏渲染页面。如果首屏渲染时间转化率对应用程序至关重要,那可以使用 SSR 来优化。

开箱即用的SSR脚手架

目前前端流行的三种技术栈 React, Vue 和 Angula,已经孵化出对应的服务端渲染框架,开箱即用,感兴趣的同学可以自主学习使用。

  • React: Next.js

  • Vue:  Nuxt.js

彻底理解服务端渲染 - SSR原理_沛沛老爹的博客-CSDN博客

服务端渲染SSR及实现原理_ssr场景_油墨香^_^的博客-CSDN博客

22  什么是 Reflect ?

Reflect 其实和 Proxy 一样都是属于 ES6 的高级API,Reflect 也是属于 window 的一个内置类,可以通过 window.Reflect 访问到,看下图    

     Reflect是JavaScript中的全局对象,提供操作JavaScript对象的方法,类似与Object操作对象的方法。用于解决Object方法过于臃肿的问题,对大多数的Object方法进行了实现,同时对于对象的操作返回操作的结果,如返回对象的set操作结果,在某些场景下可以进行监听操作。  

工具人
 

为什么 Proxy 要配合 Reflect 一起使用

①触发代理对象的劫持时保证正确的 this 上下文指向

function getPrivateProps(obj, filterFunc) {
 
  return new Proxy(obj, {
    get(obj, prop) {
      if (!filterFunc(prop)) {
        let value = Reflect.get(obj, prop);
        // 如果是方法, 将this指向修改原对象
        if (typeof value === 'function') {
          value = value.bind(obj);
        }
        return value;
      }
    },
 
    set(obj, prop, value) {
 
      if (filterFunc(prop)) {
        throw new TypeError(`Can't set property "${prop}"`);
      }
      return Reflect.set(obj, prop, value);
    },
 
    has(obj, prop) {
      return filterFunc(prop) ? false : Reflect.has(obj, prop);
    },
 
    ownKeys(obj) {
      return Reflect.ownKeys(obj).filter(prop => !filterFunc(prop));
    },
 
    getOwnPropertyDescriptor(obj, prop) {
      return filterFunc(prop) ? undefined : Reflect.getOwnPropertyDescriptor(obj, prop);
    }
 
  });
 
}
//因为私有属性 一般以 _开头 这里就简单过滤
function propFilter(prop) {
  return prop.indexOf('_') === 0;
}
 

②框架健壮性

详解Reflect:Reflect和Object的异同,Reflect的一些内置方法以及方法注意点_DCodes的博客-CSDN博客

都知道vue3响应式是Proxy实现的,进来把proxy与Reflect吃透_vue3数据响应式过程reflect_前端阿彬的博客-CSDN博客

详解Reflect:Reflect和Object的异同,Reflect的一些内置方法以及方法注意点_DCodes的博客-CSDN博客


【前端vue3面试题】2023最新面试实录vue3.0,高频10问(持续更新...)_wzySan的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/952518.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL sever中库管理

目录 一、创建数据库 1.1库界面方式 1.2SQL命令方式 二、修改数据库 2.1库界面方式 2.2SQL命令方式 三、删除数据库 3.1库界面方式 3.2SQL命令方式 四、附加和分离数据库 4.1附加和分离数据库概述 4.2作用 4.3附加和分离数据库方法 4.4示例 一、创建数据库 1.1库…

Spring——Spring读取文件

文章目录 1.通过 value 读取比较简单的配置信息2.通过ConfigurationProperties读取并与 bean 绑定3.通过ConfigurationProperties读取并校验4. PropertySource 读取指定 properties 文件5.题外话:Spring加载配置文件的优先级 很多时候我们需要将一些常用的配置信息比如阿里云os…

protobuf生成golang和grpc代码踩坑记

错误提示&#xff1a;seems to be defined in "*.proto", which is not imported by "*proto". To use it here, please add the necessary import. 这个地方主要是因为包名的问题&#xff0c;假设user.proto文件被product.proto import了&#xff0c;则u…

《Python趣味工具》——文字RPG游戏的开发(附人生选择模拟器的详细讲解及其他多种RPG游戏的源码)

今天我们来学习如何制作一个文字RPG游戏 。 内容主要分为3个部分&#xff1a; part1. 文字游戏&#xff08;MUD&#xff09;的趣味历史 part2. 文字游戏的设计方法 part3. 文字游戏功能实现 文章目录 一、文字游戏&#xff08;MUD&#xff09;的趣味历史:1. 什么是MUD游戏:2. …

未找到System.Runtime.InteropServices.Marshal.GetTypeFromCLSID(System.Guid) 方法错误

记录此问题实际上是由于.netFrame框架配置太高引起的&#xff0c;一般常见于二次开发中&#xff0c;因为二次开发一般都是引用的com组件&#xff0c;在引用过程中后台代码调用了 Method not found: System.Type System.Runtime.InteropServices.Marshal.GetTypeFromCLSID(Syste…

研发规范第十三讲:阿里 - 如何进行项目稳定性建设

研发规范第十三讲&#xff1a;阿里 - 如何进行项目稳定性建设 本文是研发规范第13讲&#xff0c;阿里巴巴高级技术专家云狄将结合自己多年的经验&#xff0c;从开发规范、开发流程、技术规划与管理三个角度出发&#xff0c;分享对技术TL这一角色的理解与思考&#xff0c;欢迎一…

2、QT的信号与槽

一、什么是信号与槽 一个对象发送一个信号出去&#xff0c;另外一个对象接收到该信号后&#xff0c;会触发相应的槽函数 二、信号与槽的语法 connect(信号的发送者&#xff0c;SIGNAL(信号名称),信号的接收者,SLOT(槽函数)); 1、写法&#xff1a; QT 4 的写法 connect(sende…

Python爬虫:一个爬取豆瓣电影人像的小案例

从谷歌浏览器的开发工具进入 选择图片右键点击检查 ![在这里插入图片描述](https://img-blog.csdnimg.cn/1b38c2a942c441fb8cb545a28bb35015.png 翻页之后发现网址变化的只有start数值&#xff0c;每次变化值为30 Python代码 import requests from bs4 import BeautifulSou…

零基础安装pycuda

零基础安装pycuda 前言安装Visual Studio安装C/C环境添加环境变量 安装pycuda查看系统位数查看python版本下载whl文件 前言 最近开始学习基于python的cuda编程&#xff0c;记录一下pycuda的安装。 在安装pycuda之前&#xff0c;首先需要有NVIDIA的独立显卡并且要安装CUDA和CUD…

程序与进程

一、程序是怎么被执行的 1.在程序中&#xff0c;由引导代码去调用程序中得main函数&#xff0c;而这个过程由链接器完成&#xff0c;链接器将引导代码链接到我们的应用程序构成可执行文件。 2.程序运行需要通过操作系统的加载器来实现&#xff0c;加载器是操作系统中的程序&a…

【javascript实操记录】

功能描述&#xff1a; 1. 利用split()方法对测试数据进行解析&#xff1a;学科&#xff0c;日期 2. 将测试数据封装成对象数组的格式 3. 使用数组的sort()方法和Date对象&#xff0c;将测试数据按照日期从早到晚进行排序 4. 表格数据的静态填充 5. 距离最近考试的倒计时天…

使用 NestJS 和 Prisma 构建 REST API

NestJS是Node.js框架之一&#xff0c;它最近获得了很多开发人员的喜爱和牵引力。本文将教你如何使用NestJS&#xff0c;Prisma&#xff0c;PostgreSQL和Swagger构建后端REST API。 文章目录 介绍您将使用的技术 先决条件假定的知识开发环境 生成 NestJS 项目创建 PostgreSQL 实…

链路聚合原理

文章目录 一、定义二、功能三、负载分担四、分类五、常用命令 首先可以看下思维导图&#xff0c;以便更好的理解接下来的内容。 一、定义 在网络中&#xff0c;端口聚合是一种将连接到同一台交换机的多个物理端口捆绑在一起&#xff0c;形成一个逻辑端口的技术。通过端口聚合&…

数据结构--5.0.1图的存储结构

目录 一、邻接矩阵&#xff08;无向图&#xff09; 二、邻接矩阵&#xff08;有向图&#xff09; 三、邻接矩阵&#xff08;网&#xff09; 四、邻接表&#xff08;无向图&#xff09; 五、邻接表&#xff08;有向图&#xff09; ——图的存储结构相比较线性表与树来说就复…

AIGC全流程赋能:从剧本到宣发,影视内容全新呈现

“猕猴桃”视频平台在今日发布了2023年第二季度财报&#xff0c;首次公布引入AIGC辅助剧本评估。内部数据显示&#xff0c;AIGC帮助提升剧本评估、预算规划等效率超过90%。“猕猴桃”视频平台还通过AIGC技术实现对影视剧的剧情理解&#xff0c;从而改进搜索结果、推荐和用户互动…

kubernetes deploy standalone mysql demo

kubernetes 集群内部署 单节点 mysql ansible all -m shell -a "mkdir -p /mnt/mysql/data"cat mysql-pv-pvc.yaml apiVersion: v1 kind: PersistentVolume metadata:name: mysql-pv-volumelabels:type: local spec:storageClassName: manualcapacity:storage: 5Gi…

IAR 编译优化 #pragma optimize

在IAR工具菜单栏中 点击 【help】-> 【Serach】 搜索optimize #pragma optimize[goal][level][vectorize][disable] 如果想设置优化速度到最高等级,则如下设置即可 #pragma optimizespeed high int SmallAndUsedOften() { /* Do something here. */ }

分布式事务学习笔记

MySQL事务 1、 MySQL事务隔离级别 读未提交 &#xff08;READ UNCOMMITTED&#xff09; &#xff08;存在脏读的问题&#xff09;读已提交&#xff08;READ COMMITTED&#xff09;可重复读&#xff08;REPEATABLE READ&#xff09;串行化&#xff08;SERIALIZABLE&#xff09;…

LCD驱动

一、Linux 下 LCD 驱动简析 1.与裸机的异同 在 Linux 中应用程序最终也是通过操作 RGB LCD 的显存来实现在 LCD 上显示字符、图片等信息&#xff0c;但是Linux系统的内存管理严格&#xff0c;使用显存需要申请&#xff0c;因为虚拟内存的存在&#xff0c;驱动程序设置的显存和应…

python 栈、用栈实现综合计算器

栈的基本介绍 出栈&#xff08;pop&#xff09;示意图 入栈&#xff08;push&#xff09;示意图 栈的应用场景 数组模拟栈 思路分析 代码实现 # 用数组模拟栈 class ArrayStack:def __init__(self, size):self.max_size size # 栈的最大容量self.top -1 # top 表示栈顶…