88道Vue高频题整理(附答案背诵版)
1、请简述Vue插件和组件的区别 ?
Vue的插件(Plugin)和组件(Component)是Vue.js中非常重要的两个概念,它们在功能上有着明显的差异。
- Vue组件(Component): Vue组件是Vue.js最强大的功能之一。组件可以扩展HTML元素,封装可重用的代码。在较大的Vue.js应用中,我们会把整个应用拆分成一些小的、独立的、可复用的组件以使整个项目结构更清晰。例如,一个电商网站的页面可以被拆分为头部组件,侧边栏组件,产品列表组件等。
- Vue插件(Plugin): Vue插件通常用来为Vue添加全局功能。插件的范围没有严格的限制——通常是添加全局方法或者通过全局混入等方式影响Vue构造器,也可以提供额外的命令行选项。它可能会为Vue添加全局方法或属性(如vue-custom-element),提供一些自定义选项,或者向Vue实例添加方法。例如,Vue Router和Vuex就是Vue的插件。
简单来说,Vue组件是Vue应用的一部分,用于封装和重用代码,而Vue插件则是用于添加全局级别的功能。
2、简述Vue的MVVM 模式?
MVVM模式是Model-View-ViewModel的缩写,是一种设计思想。MVVM模式分为三部分:
- Model(模型):负责数据的存储以及处理问题的部分,它代表的是你的数据和业务逻辑。在Vue中,Model就是我们在data中声明的数据。
- View(视图):负责数据展示的部分,简单来说,就是用户看到并与之交互的界面。在Vue中,View就是我们写的模板。
- ViewModel(视图模型):它是连接View和Model的桥梁。在Vue中,ViewModel就是Vue实例。Vue实例在创建时,会接收data对象,并遍历此对象所有的属性,并使用Object.defineProperty将属性全部转为getter/setter,以便追踪属性的变化。当用户在View层进行操作时,ViewModel能感知到变化并对Model层的数据进行更新,反之亦然。
MVVM的最大优点就是数据驱动和双向数据绑定,即Model变化会自动更新到View,反之View变化也会自动改变Model。这种方式让开发者只需关注业务逻辑,不需要手动操作DOM,极大地提高了开发效率。
3、简述MVC与MVVM的区别 ?
MVC 和 MVVM 都是常见的设计模式,它们的主要区别在于对视图和业务逻辑的处理方式。
-
MVC(Model-View-Controller)模式:
- Model(模型):负责数据的存储。
- View(视图):负责数据展示。
- Controller(控制器):作为模型和视图之间的桥梁,处理用户交互,并更新视图和模型。
在MVC模式中,用户的操作会首先到达控制器,然后控制器更新模型,模型变化后会反过来更新视图。但是,这种模式的问题在于,控制器可能变得过于复杂,因为它需要处理视图和模型之间的所有交互。
-
MVVM(Model-View-ViewModel)模式:
- Model(模型):负责数据的存储。
- View(视图):负责数据展示。
- ViewModel(视图模型):作为模型和视图之间的桥梁,处理用户交互,并更新视图和模型。
MVVM模式的出现是为了解决MVC中控制器过于复杂的问题。在MVVM中,视图模型替代了控制器的角色,它使用数据绑定的方式来实现视图和模型的同步。当模型的数据发生变化时,视图模型会自动更新视图,反之亦然。这种方式降低了视图和模型之间的耦合度,使得代码更易于管理和维护。
总的来说,MVVM相比MVC,更加注重数据驱动和视图的自动更新,使得开发者可以更专注于业务逻辑,而不需要手动操作DOM,提高了开发效率。
4、简述Vue组件通讯有哪些方式 ?
Vue组件间的通信主要有以下几种方式:
-
父子组件通信:
- Props down / Events up:父组件通过 props 向子组件传递数据,子组件通过 emit 发送事件来通知父组件数据的变更。
- 使用
$refs
:父组件可以通过$refs
获取子组件的实例,从而访问其数据和方法。 .sync
修饰符:Vue 2.3.0 版本引入了.sync
修饰符,可以作为一种双向绑定的语法糖,方便父子组件间的数据同步。
-
非父子组件通信:
- 事件总线(Event Bus):创建一个新的 Vue 实例作为事件总线,在需要通信的组件之间触发和监听事件。
- Vuex:Vue 的官方状态管理工具,能够帮助我们管理共享状态,非常适合大型应用。
- Vue Router:如果使用了 Vue Router,可以通过路由参数进行通信。
-
跨级组件通信:
$parent
/$children
:访问父/子组件实例。- provide/inject:Vue 提供的依赖注入机制,能够实现祖先组件向后代组件注入数据或方法。
以上就是Vue中常见的组件间通信方式,选择哪种方式取决于具体的应用场景和需求。
5、简述Vue的生命周期方法有哪些?
Vue实例从创建到销毁的过程,就是生命周期。Vue的生命周期主要包括以下几个阶段:
-
创建阶段:
beforeCreate
:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。created
:在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch
/event
事件回调。然而,挂载阶段还没开始,$el
属性目前不可见。
-
挂载阶段:
beforeMount
:在挂载开始之前被调用。相关的render
函数首次被调用。mounted
:el
被新创建的vm.$el
替换,并挂载到实例上去之后调用。此时,你会有一些直接的 DOM 操作任务需要在这个阶段完成。
-
更新阶段:
beforeUpdate
:数据更新时调用,发生在虚拟DOM打补丁之前。这里适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器。updated
:由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。
-
销毁阶段:
beforeDestroy
:实例销毁之前调用。在这一步,实例仍然完全可用。destroyed
:Vue实例销毁后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。
这些生命周期钩子函数为用户在不同阶段添加自己的代码提供了便利,比如你可以在 created
钩子函数中进行Ajax请求数据,在 mounted
钩子函数中操作DOM等。
6、简述 v-if 和 v-show 的区别 ?
v-if
和 v-show
都是 Vue 中用来进行条件渲染的指令,但它们之间有一些重要的区别:
v-if
:是“真正的”条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。简单来说,如果条件为假,v-if
指令会完全销毁元素。v-show
:不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。v-show
只会在元素上切换 CSS 的display
属性。如果条件为假,v-show
指令只会将元素隐藏,而不是销毁。
总的来说,v-if
有更高的切换消耗,v-show
有更高的初始渲染消耗。因此,如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好。
7、简述 Vue 有哪些内置指令 ?
Vue提供了一些内置指令,可以在模板中进行一些常见的任务。以下是一些最常用的内置指令:
v-bind
:用于绑定一个属性到表达式。简写为:
。例如,v-bind:class
可以绑定一个 class 到一个表达式。v-model
:在表单元素或者组件上创建双向数据绑定。v-show
:根据表达式之真假值,切换元素的显示/隐藏状态。v-if
、v-else-if
、v-else
:根据表达式的值的真假,在DOM中渲染或者销毁元素。v-for
:基于源数据多次渲染元素或模板块。v-on
:绑定事件监听器。事件类型由参数指定。简写为@
。例如,v-on:click
可以监听一个点击事件。v-text
:更新元素的textContent
。如果要更新部分的textContent
,需要使用{{ Mustache }}
插值。v-html
:更新元素的innerHTML
。注意,内容按普通 HTML 插入 - 不会作为 Vue 模板进行编译。v-cloak
:这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如[v-cloak] { display: none }
一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。v-pre
:跳过这个元素和它的子元素的编译过程。可以用来显示原始的 Mustache 标签。跳过大量没有指令的节点会加快编译。v-once
:只渲染元素和组件一次。随后的重新渲染, 元素/组件及其所有的子节点将被视为静态内容并跳过。
这些内置指令大大增强了模板的功能,使我们可以在模板中实现更多的逻辑。
8、简述Vue computed 和 watch 的区别和运用的场景 ?
computed
和 watch
都是 Vue 中的重要特性,它们都用于观察和响应 Vue 实例上的数据变动。但是它们的使用场景和方式有所不同:
-
computed
(计算属性):- 计算属性是基于它们的依赖进行缓存的。只有在相关依赖发生改变时才会重新求值。这意味着只要依赖没有改变,多次访问计算属性会立即返回之前的计算结果,而不必再次执行函数。
- 计算属性适合用在模板渲染中,某个值是依赖其他的响应式对象甚至多个计算属性计算而来;当这些依赖发生变化时,计算属性会重新计算新的值。这使得我们在处理复杂逻辑时,能够将复杂逻辑拆分在各个计算属性中,使得代码更清晰易读。
-
watch
(侦听器):- 侦听器允许我们对数据进行异步操作,每当监听的数据变化时,都会执行回调进行后续操作。
- 当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。例如,当一些数据改变需要向服务器发送请求,或者在数据改变后需要进行一些延时的复杂逻辑,这些场景下,使用
watch
是非常有用的。
总的来说,当你需要在数据变化后执行异步或开销较大的操作时,使用 watch
;当你需要根据其他数据变动实时计算或处理一些数据时,使用 computed
。
9、简述 Vue 2.0 响应式数据的原理( 重点 )?
Vue 2.0 的响应式系统的核心是 Object.defineProperty,它允许 Vue 跟踪依赖,并在属性被访问和修改时通知变更。以下是 Vue 2.0 响应式数据的原理:
- 当你把一个普通的 JavaScript 对象传给 Vue 实例的
data
选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。 - 每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据属性记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
- Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际(已去重的)工作。
- Vue 在内部尝试对异步队列使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。
通过这种方式,Vue 能够智能地知道何时更新视图,而无需在数据变化时手动操作 DOM,这大大提高了应用的效率。
10、请解释Vue的父子组件生命周期钩子函数执行顺序 ?
Vue.js中的每个组件都有自己的生命周期,从创建(creation)到挂载(mounting),更新(updating)和销毁(destruction)。在这个过程中,Vue提供了一些生命周期钩子函数,如 created
, mounted
, updated
, destroyed
等,这些函数可以让我们在特定的时机执行一些代码。
当一个父组件包含一个子组件时,他们的生命周期钩子函数的执行顺序如下:
beforeCreate
: 父组件首先执行beforeCreate
钩子函数。created
: 父组件接着执行created
钩子函数。beforeMount
: 父组件接着执行beforeMount
钩子函数。然后开始处理子组件。beforeCreate
: 子组件执行beforeCreate
钩子函数。created
: 子组件接着执行created
钩子函数。beforeMount
: 子组件接着执行beforeMount
钩子函数。mounted
: 子组件首先执行mounted
钩子函数,然后父组件执行mounted
钩子函数。这是因为父组件等待其所有子组件都挂载完成后,才会执行自己的mounted
钩子函数。
当组件更新时,执行顺序如下:
beforeUpdate
: 父组件首先执行beforeUpdate
,然后子组件执行beforeUpdate
。updated
: 子组件首先执行updated
,然后父组件执行updated
。
当组件销毁时,执行顺序如下:
beforeDestroy
: 父组件首先执行beforeDestroy
,然后子组件执行beforeDestroy
。destroyed
: 子组件首先执行destroyed
,然后父组件执行destroyed
。
这个顺序很重要,因为它决定了我们可以在哪个钩子函数中进行数据获取、操作DOM等操作。例如,如果我们想在组件挂载后操作DOM,那么我们应该在mounted
钩子函数中进行。
11、简述 v-model 双向绑定的原理是什么?
v-model
是 Vue.js 中的一个重要指令,它实现了数据和表单元素之间的双向绑定。简单来说,双向绑定就是数据改变会影响视图,视图改变也会影响数据。
v-model
的双向绑定原理主要基于以下两个部分:
- 数据到视图的绑定:这一部分主要通过 Vue 的响应式系统完成。当我们在组件的 data 中定义一个变量,例如
message
,Vue 会使用 Object.defineProperty() 方法将它转换为 getter/setter。当我们在模板中使用{{message}}
或v-model="message"
时,Vue 会将当前组件添加到message
的依赖中。当message
发生变化时,Vue 会通知所有依赖message
的组件重新渲染,从而更新视图。 - 视图到数据的绑定:这部分主要通过监听 DOM 事件完成。对于
<input>
元素,v-model
指令会监听input
事件。当用户在输入框中输入内容时,触发input
事件,然后v-model
指令的事件处理函数会把新的值赋给message
,从而更新数据。
所以,v-model="message"
相当于 v-bind:value="message"
和 v-on:input="message = $event.target.value"
的语法糖。
这种双向绑定机制使得我们在处理表单元素时更加简单,只需要操作数据,不需要直接操作 DOM,提高了开发效率。
12、请简述Vue3.x 响应式数据原理是什么?( 重点 )
Vue 3.x 的响应式系统是基于 ES6 的 Proxy
对象和 Reflect
对象实现的,相比于 Vue 2.x 使用的 Object.defineProperty
,Proxy
可以直接监听对象而非属性,它可以拦截并定义基本操作的行为,如属性查找、赋值、枚举、删除等。
下面是 Vue 3.x 响应式系统的基本原理:
- 数据劫持:当我们使用
reactive
或ref
创建响应式数据时,Vue 3.x 会使用Proxy
创建一个代理对象,对原始对象进行劫持。Proxy
可以拦截对象的多种操作,包括获取属性值、设置属性值、删除属性等。 - 依赖收集:当我们首次访问属性值时,
Proxy
的get
陷阱会被触发。在get
陷阱中,Vue 3.x 会把当前正在执行的副作用函数(即响应式效果函数)添加到当前属性的依赖列表中。这个过程叫做依赖收集。 - 派发更新:当我们修改属性值时,
Proxy
的set
陷阱会被触发。在set
陷阱中,Vue 3.x 会遍历当前属性的依赖列表,执行每个依赖(副作用函数)。这个过程叫做派发更新。
举个例子,假设我们有一个响应式对象 data
:
const data = reactive({ count: 0 });
当我们在组件的 setup
函数中使用 data.count
时:
watchEffect(() => {
console.log(data.count);
});
Vue 3.x 会在 Proxy
的 get
陷阱中,把 console.log(data.count)
这个副作用函数添加到 count
属性的依赖列表中。
当我们修改 data.count
时:
data.count++;
Vue 3.x 会在 Proxy
的 set
陷阱中,遍历 count
属性的依赖列表,执行每个副作用函数。所以,console.log(data.count)
会被执行,打印出新的 count
值。
通过这种方式,Vue 3.x 实现了数据的响应式。只要数据发生变化,所有依赖这个数据的地方都会自动更新。
13、请简述vue-router 动态路由是什么?
Vue-router 的动态路由主要是指路由的路径中包含动态部分,也就是说,我们可以在一个路由中插入一些变量。
动态路由主要用于处理 URL 参数,使我们能够创建一个路由来匹配任意路径,其中包含的参数可以在 Vue 组件中获取。
例如,我们可能有一个用户组件,用于显示用户的详细信息。每个用户都有一个唯一的 ID。我们可以创建一个动态路由来匹配 "/user/:id",其中 ":id" 是一个动态的部分,可以匹配任意的用户 ID:
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User }
]
})
这样,当我们访问 "/user/123" 时,Vue-router 会显示 User 组件,并将 "123" 作为参数传递给它。
在 User 组件中,我们可以使用 $route.params.id
来获取用户 ID:
export default {
computed: {
userId() {
return this.$route.params.id
}
}
}
这种方式使得我们能够使用同一个组件来显示不同的用户,而不需要为每个用户都创建一个单独的路由和组件,从而简化了代码的复杂性并提高了代码的重用性。
14、Vue生命周期钩子是如何实现的?
Vue 的生命周期钩子函数是 Vue 实例在不同生命周期阶段会自动调用的一些函数。这些函数让我们有机会在特定的时刻添加自己的代码,如在组件创建时获取数据,在组件更新前做一些清理工作等。
Vue 的生命周期钩子的实现主要依赖于 Vue 的组件系统。在 Vue 内部,每个 Vue 组件都被表示为一个 Vue 实例,在这个实例的生命周期中,Vue 会在特定的时机调用相应的钩子函数。
以下是 Vue 生命周期钩子函数的主要实现过程:
- 创建阶段:当我们使用
new Vue()
创建一个新的 Vue 实例时,Vue 会调用_init
方法来初始化这个实例。在_init
方法中,Vue 会调用beforeCreate
和created
钩子函数。在这两个钩子函数中,我们可以访问到组件的数据和方法,但是无法访问到 DOM,因为此时 DOM 还没有被创建。 - 挂载阶段:当我们调用
vm.$mount()
方法来挂载这个 Vue 实例时,Vue 会开始编译模板并创建 DOM。在这个过程中,Vue 会调用beforeMount
和mounted
钩子函数。在beforeMount
钩子函数中,我们可以获取到编译后的模板,但是无法获取到 DOM,因为此时 DOM 还没有被插入到页面中。在mounted
钩子函数中,我们可以获取到 DOM,并可以进行 DOM 操作。 - 更新阶段:当组件的数据发生变化时,Vue 会重新渲染组件。在这个过程中,Vue 会调用
beforeUpdate
和updated
钩子函数。在beforeUpdate
钩子函数中,我们可以获取到更新前的数据和 DOM。在updated
钩子函数中,我们可以获取到更新后的数据和 DOM。 - 销毁阶段:当我们调用
vm.$destroy()
方法来销毁这个 Vue 实例时,Vue 会开始销毁组件。在这个过程中,Vue 会调用beforeDestroy
和destroyed
钩子函数。在beforeDestroy
钩子函数中,我们可以获取到销毁前的数据和 DOM,并可以进行一些清理工作,如清除定时器、取消事件监听等。在destroyed
钩子函数中,我们可以确认组件已经被销毁,所有的数据和方法都已经被清除。
以上就是 Vue 生命周期钩子函数的主要实现过程。需要注意的是,这些钩子函数都是可选的,我们可以根据需要在组件中定义这些函数。当这些函数存在时,Vue 会在相应的时机自动调用它们。
15、如何理解Vue中的模板编译原理?
Vue.js的模板编译原理主要包括两个步骤:解析(Parse)和生成(Generate)。
-
解析(Parse) :这个阶段会把模板转换成抽象语法树(AST,Abstract Syntax Tree)。抽象语法树是一种以树状的形式表现源代码结构的方式,每一个节点都代表源代码中的一部分。
解析阶段主要做的就是读取模板中的标签、指令、插值等,并以抽象语法树的形式表现出来。例如,对于模板
<div id="app">{{ message }}</div>
,解析后的抽象语法树可能如下:{ type: 1, // 节点类型,1表示元素节点 tag: 'div', // 标签名 attrsList: [{ name: 'id', value: 'app' }], // 属性列表 attrsMap: { id: 'app' }, // 属性映射 children: [ // 子节点列表 { type: 2, // 节点类型,2表示带有插值的文本节点 expression: '_s(message)', // 插值表达式 text: '{{ message }}' // 文本内容 } ] }
-
生成(Generate) :这个阶段会把抽象语法树转换成渲染函数。渲染函数是一个JavaScript函数,当执行这个函数时,会返回一个虚拟DOM。
生成阶段主要做的就是遍历抽象语法树,把每一个节点转换成虚拟DOM的创建代码。例如,对于上面的抽象语法树,生成后的渲染函数可能如下:
function render() { return _c('div', { attrs: { id: 'app' } }, [_v(_s(message))]); }
其中,
_c
是创建元素节点的函数,_v
是创建文本节点的函数,_s
是转换为字符串的函数。
这就是Vue.js的模板编译原理的基本过程。通过这个过程,Vue.js可以把我们写的模板转换成JavaScript代码,从而实现数据和视图的绑定。
16、简述vue.mixin的使用场景和原理?
Vue 的 mixin 是一种分发 Vue 组件中可复用功能的非常灵活的方式。简单来说,mixin 对象可以包含任何组件选项,当组件使用 mixin 对象时,所有 mixin 对象的选项将被混入到该组件本身的选项中。
使用场景:
- 当我们有一些通用的功能,比如数据获取、验证函数、工具方法等,这些功能在多个组件中都需要使用时,就可以考虑使用 mixin 来进行代码复用。
- 当我们需要对 Vue 的一些生命周期钩子函数进行抽象时,也可以使用 mixin。例如,我们可以创建一个 mixin,它在
created
钩子中获取数据,在beforeDestroy
钩子中清理资源。
代码示例:
// 定义一个 mixin 对象
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
// 定义一个使用了这个 mixin 的组件
var Component = Vue.extend({
mixins: [myMixin]
})
var component = new Component() // => "hello from mixin!"
原理:
Vue 的 mixin 实现原理主要是通过合并选项(merge options)来实现的。当我们创建一个 Vue 实例或组件时,Vue 会把这个实例或组件的选项和所有的 mixin 对象的选项进行合并。这个合并过程主要是通过 Vue.config.optionMergeStrategies
来实现的,它定义了各种选项的合并策略。
在合并过程中,大部分选项将进行合并,也就是说,如果组件和 mixin 对象都定义了这个选项,那么最终的结果将是这两个选项合并后的结果。例如,对于 data
选项,Vue 会把组件和 mixin 对象的数据对象进行合并,并返回一个新的数据对象。
但是有一些选项是不进行合并的,比如 el
和 data
。对于这些选项,如果组件和 mixin 对象都定义了这个选项,那么最终的结果将是组件的选项覆盖 mixin 对象的选项。
通过这种方式,Vue 的 mixin 实现了对组件选项的复用,使我们可以在多个组件中共享同样的选项和逻辑。
由于内容太多,更多内容以链接形势给大家,点击进去就是答案了
25. 请简述Vue 的性能优化可以从哪几个方面去思考设计 ?
27. 请解释Vue为什么要用虚拟Dom ,详细解释原理 ?
34. Vue中delete和Vue.delete删除数组的区别 ?
36. 请说明Vue中$root、$refs、$parent的使用 ?
37. 简述v-el 作用是什么以及Vue的el属性和$mount优先级?
38. 简述vue-loader是什么?使用它的用途有哪些?
39. 简述Vue的普通Slot以及作用域Slot的区别 ?
41. Vue3.0 里为什么要用 Proxy API替代 defineProperty API?
47. Vue 3.0 所采用的 Composition Api 与 Vue 2.x使用的Options Api 有什么区别?
48. Vue.js中的v-bind指令有何作用?如何使用?
50. 简述父组件给子组件props传参,子组件接收的6种方法 ?
54. 简述vue2.x 和 vuex3.x 渲染器的 diff 算法 ?
56. 请简述构建 vue-cli 工程都用到了哪些技术?他们的作用分别是什么?
58. 简述Vue complier 的实现原理是什么样的?
61. Vue.extend 和 Vue.component 的区别是什么?
62. 简述接口请求一般放在哪个生命周期中?为什么要这样做?
66. 阐述Vue 中 computed 和 methods 的区别 ?
67. 如何监听 pushstate 和 replacestate 的变化呢?
70. Vue中子组件可以直接改变父组件的数据么,说明原因 ?
78. 简述vue深拷贝,数量加减dom不进行二次渲染,解决方法 ?
80. 简述React 和 Vue 的 diff 时间复杂度从 O(n^3) 优化 到 O(n) ,那么 O(n^3) 和 O(n) 是如何计算出来的 ?
81. 简述Vue 的⽗组件和⼦组件⽣命周期钩⼦执⾏顺序是什么 ?
82. 简述Vue data 中某一个属性的值发生改变后,视图会立即同步执 行重新渲染吗 ?
84. 简述v-if 和 v-for 哪个优先级更高?如果同时出现,应如何优化 ? 在 Vue 中,`v-