VUE3面试题个人总结

  1. vue3的编译流程?
  2. vue3内的宏是什么?
  3. <script setup/>的实现原理?
  4. 组件实例是什么?
  5. 启动程序的时候,vue3单文件组件的初始化流程?
  6. createApp()mount()做了什么工作?
  7. 组件的生命周期?
  8. 什么是虚拟DOM?diff算法?就地复用?
  9. 任务调度系统?
  10. 异步刷新是什么?怎么实现的?
  11. nextTick()的实现原理?
  12. 有哪三种Effect?作用?
  13. watch()watchEffect()computed()的区别?
  14. 响应式编程的实现原理?
  15. ref()reactive()的区别?
  16. ref()ref(null)的区别?
  17. attrsprops的区别?
  18. provideinject实现原理?
  19. emit()的实现原理?
  20. 单向数据流的原因?
  21. 模板的编译流程?在什么时候编译?
  22. 组件的注册是什么?
  23. 指令的实现原理?
  24. 各种指令的区别和作用?
  25. v-for为什么要加key?v-for为什么不能和v-if一起使用?
  26. v-model的实现原理?
  27. hook是什么?
  28. 插件是什么?实现原理?
  29. 什么是异步组件?实现原理?
  30. 前端路由是什么?什么是路由懒加载?

    问题

    (1)vue3编译流程?

    vue3的编译分两部分:编译期和运行期。编译期间,先通过vue-loader把单文件组件编译成符合原生JavaScript语法的模块;运行期间,会通过内置的模板引擎对模板进行编译,生成 render()函数,且按照先父组件后子组件的顺序对模板进行编译。

    (2)vue3内的宏是什么?和语法糖的区别?

    按照vue3官方的说法, defineProps() 、 defineEmits()defineExpose()都是宏,它们使用形式上和函数调用差不多,区别是,第一,这些宏不需要通过模块导入;第二,这些宏会在编译期被编译成符合JavaScript原生语法的代码。语法糖也会被编译成符合JavaScript原生语法的代码,vue3官方对这两者进行区分是因为,语法糖创建的是不曾有过的语法,而宏指的是给现有语法新的含义。

    (3)<script setup/>的实现原理?

    <script setup/>本质是 setup()函数的语法糖,vue-loader在编译期间会把 <script setup/>内的代码编译成 setup()函数,把 defineExpose()内指定的变量编译为setup()函数的返回值。

    (4)组件实例是什么?

    每个单文件组件都有一个组件实例,组件实例是用来存放组件状态的,可以在 setup()函数内,通过 getCurrentInstance()获取组件实例。

    (5)启动程序的时候,vue3单文件组件的初始化流程?

    单文件组件由组件实例、相应vnode、相应node三部分组成。初始化的时候,先创建组件的实例;接着用父组件vnode初始化实例的 propsattrsslots成员;然后执行 setup()函数;接着把模板编译成 render()函数;接着创建vnode;如果当前组件有子组件,则切换到子组件,重复上面的步骤;子组件都初始化完成后,把vnode同步到node上。

    (6)createApp()mount()做了什么工作?

    程序在初始化的时候会依次调用 createApp()mount()函数, createApp()负责执行平台相关的代码, mount()负责执行平台无关的代码。 createApp()主要做了两件事,第一,创建一个渲染器,它可用于把vdom转化为平台相关的界面代码;第二,返回一个 App实例。 mount()的作用就是,创建组件实例、vdom、完成依赖收集、并通过渲染器把vdom渲染成平台相关的界面代码。

    (7)组件的生命周期?

    单个组件的生命周期:初始化阶段,先执行setup函数初始化实例,接着执行 onBeforeMount,最后执行 onMounted;运行阶段,先执行 onBeforeUpdate,再执行 onUpdated;关闭阶段,先执行 onBeforeUnmount,再执行 onMounted
    父子组件的生命周期:初始化阶段,先执行父组件的 onBeforeMount,然后执行子组件的 onBeforeMount,接着执行子组件的 onMounted,最后执行父组件的 onMounted;运行阶段、关闭阶段同理可推。

    (8)什么是虚拟DOM?diff算法?

    虚拟dom是用JavaScript语言描述的一个树形结构,用于缓存发生变化的响应式数据,当到达下次刷新周期的时候,一次性把所有发生变化的数据同步到实际dom上。diff算法是同步vdom和dom数据的算法,采用就地复用的策略实现高效同步。

    (9)任务调度系统?

    vue3内部维持了3类队列:pre队列——组件更新前置任务队列;queue队列——组件更新时的任务队列;post队列——组件更新后置任务队列。vue3内所有异步任务都会被推进这些队列,当本次宏任务执行结束的时候,会执行一个名为flushJob的微任务,该微任务会按照pre>queue>post的优先级,依次执行每个队列中的函数。

    (10)异步刷新是什么?怎么实现的?

    异步刷新指的是在响应式数据发生更改后,只更新vdom,不立即更新dom,当下一个刷新周期到来的时候,次性把所有发生变化的数据同步到实际dom上。
    异步刷新是通过job队列+Promise+diff算法实现的,当响应式数据发生更改时候,会立即更新vdom上的数据,待下个刷新周期到来的前,开始执行flushJob微任务,flushJob会通过diff算法完成vdom和dom之间的数据同步。

    (11)nextTick()的实现原理?

    nextTick()作用是,让回调函数在下一次刷新DOM的时候,具体来说在onUpdated后执行。vue3内的nextTick()是通过Promise实现,当微任务flushJob把Job队列中的所有函数都执行完了后,nextTick()回调会被推入微任务队列,然后开始执行。

    (12)有哪三种Effect?作用?

    vue3组件内有3类Effect: computedEffectwatchEffectrenderEffect。正是通过这些Effect才实现数据可监听函数的绑定,其中 computedEffectwatchEffectsetup()期间创建,而 renderEffectonBeforeMountonMounted之间创建。

    (13)watch()watchEffect()computed()的区别?

    三者都用于实现数据和监听函数的绑定。原理上来说,三者的共同点是,都会在setup期间、即onBeforeMount之前,创建一个Effect对象,并执行依赖收集函数进行依赖收集。区别是,第一,watchEffect、computed的依赖收集函数和监听函数是同一个函数,而watch的依赖收集函数和回调函数是两个函数,这就导致了watchEffect和computed参数中的监听函数会在程序初始化期间执行一次,而watch参数中的监听函数默认不会执行;第二,computed参数中的监听函数在变量发生变化后立即执行,watchEffect、watch参数中的监听函数执行时机可由用户指定,可以立即执行,也可以异步执行。

    (14)响应式编程的实现原理?

    响应式编程的核心是通过发布订阅模式、Effect对象、重写get函数实现的。发布订阅模式实现数据和监听函数的绑定,Effect对象内封装有监听函数和调度策略,get函数则负责进行依赖收集和返回数据。

    (15)ref()reactive()的区别?

    两者都用于实现响应式变量,区别在于 reactive()只可以封装引用类型, ref()可以封装任意类型; reactive()通过 Proxy实现, ref()通过类封装,并重写 get/set实现。就目前而言,要访问 ref()封装的变量,需要通过 value函数获取。

    (16)ref()ref(null)的区别?

    ref()的作用是封装普通数据,实现响应式数据; ref(null)的作用是获取子组件实例。

    (17)attrsprops的区别?

    attrsprops的作用都是,以模板属性的形式,从父组件传递数据给子组件。区别是,子组件中获取从父组件传过来的 props数据,首先需要用 defineProps()声明,而获取 attrs数据不需要声明。 props的优势是增加了代码可读性, attrs的优势是传值更灵活、代码更简洁。

    (18)provide()inject()实现原理?

    在祖先组件里通过 provide()提供的数据,可以在任意子孙组件里通过 inject()获取。它是通过原型链实现的。

    (19)emit()的实现原理?

    emit()是通过发布订阅模式实现的,子组件发送一个事件,父组件收到该事件会立即执行相应的函数。

    (20)单向数据流的原因?

    单向数据流指的是在 vue中约定,父组件传递给子组件的数据只能单向流动。也就是说,当一个父组件将其数据传递给一个子组件时,子组件不能直接修改该数据,而是需要通过向父组件发送事件来请求更改该数据。这种单向数据流的方式可以确保应用程序的数据流向清晰明确,易于理解和维护。

    (21)模板的编译流程?在什么时候编译?

    模板会先被解析成AST对象,然后通过遍历AST对象生成渲染函数。这个过程发生在 setup()函数执行结束后、 onBeforeMount之前。

    (22)组件注册是什么?

    若要在vue内使用自定义组件,需要先注册组件。组件注册可以看作是一种声明,用于告诉编译器,某个标签名是组件。组件注册分为局部注册和全局注册,全局注册的组件可以在整个程序内使用,局部注册的组件只可以在特定组件内使用。

    (23)指令的实现原理?

    vue3内的指令是,本质上是一系列钩子函数的集合,可以为这些钩子函数指定执行时机,包括: onBeforeMountonMountedonBeforeUpdateonUpdatedonBeforeUnmountonUnmounted

    (24)各种指令的区别和作用?

    v-showv-if的区别: v-show=false的组件会被创建,但是不会显示; v-if=false的组件不会被创建。
    v-onv-bind的区别: v-on用于绑定事件和事件处理函数; v-bind用于绑定变量。
    v-textv-html和插值表达式的区别:插值表达式存在闪屏的问题,而 v-text 、 v-html不存在该问题;插值表达式和 v-text都会直接以字符串的形式显示html, v-html则可以渲染html标签对。

    (25)v-for为什么要加key?v-for为什么不能和v-if一起使用?

    v-for要加key是因为,第一,vue的同步算法采用就地复用的策略,在没有key值的情况下,diff算法认为标签类型相同的元素可以进行复用;有key值的情况下,diff算法认为标签类型相同且key值相等的元素才可以复用。第二,vue只在 v-model实现了数据双向绑定,其它地方实现的都是单向绑定, <input/>框内的文字发生变化,不会实时同步到数据上。
    在vue3中, v-if的优先级高于 v-for,导致 v-if访问不了 v-for中的变量,因此不能把  v-if 和  v-for 同时用在同一个元素上。

    (26)v-model的实现原理?

    v-model实现了数据的双向绑定,它是通过响应式数据+监听输入框事件实现的。

    (27)hook是什么?

    hook是一种编程封装思想,通过闭包实现,早在ES6诞生之前,这种编程封装思想在JavaScript中应用广泛,只不过在React17出现后,React官方把这种思想命名为hook,vue3借鉴react命名,也把这种封装思想称作hook。

    (28)vue3插件是什么?

    vue3内的所谓的插件不是常规意义上的插件,而是指mount()前执行的初始化函数,vue插件通常用来为 vue 添加全局功能。vue3内通过use()函数引入插件,use()的作用就是执行参数对象内的install()函数。

    (29)什么是异步组件?

    网页的渲染流程一般分两部,先从网络加载网页,然后渲染。异步组件指的是,首次加载和渲染网页的时候,不从网络上加载该组件对应的JavaScript文件,而是等到需要显示该组件的时候,再从网络上加载该组件并渲染显示出来。

    (30)前端路由是什么?什么是路由懒加载?

    路由能够根据不同的URL地址返回给用户不同的内容或页面,如果路由位于浏览器端,就是前端路由;如果路由位于服务器端,就是后端路由。
    对于SPA单页应用,打包构建时,JavaScript包会变得非常大,会使得页面首次加载的时间变长 。若将不同路由对应的组件分割成不同的文件,然后当路由被访问的时候才从服务器加载对应文件,这就是路由的懒加载。

猜你喜欢

转载自blog.csdn.net/pidanl/article/details/131677032
今日推荐