响应式区别
在 Vue 2 中,使用了 Object.defineProperty 来实现数据的响应式。它通过逐个定义对象属性的方式来进行数据的劫持和监听。这种方式存在一些限制,例如无法监听新增的属性,需要使用 Vue 提供的 $set 方法来实现响应式。此外,由于需要逐个定义属性,对于大型对象或数组的性能不够理想。
而在 Vue 3 中,使用了 Proxy 来实现响应式系统。Proxy 是 ES6 提供的一种代理机制,可以拦截对象的操作。Vue 3 使用 Proxy 来创建一个中间代理,该代理会拦截对数据的访问和修改,并触发相应的响应。相较于 Vue 2 的 Object.defineProperty,Proxy 提供了更强大的功能和性能优势。
使用 Proxy 实现的响应式系统具有以下优势:
- 可以监听新增和删除的属性:Proxy 可以监听对象的整个访问和修改过程,包括属性的新增和删除。这意味着无需特殊处理,即可实现对新增属性的监听。
- 性能更好:Proxy 的实现方式比 Object.defineProperty 更高效。它可以一次性拦截整个对象或数组,而不需要逐个定义属性,因此在处理大型对象或数组时具有更好的性能。
- 扩展性更好:Proxy 提供了丰富的拦截器方法,可以拦截对象的各种操作,例如读取属性、修改属性、删除属性等。这使得开发者可以根据需求自定义拦截器的行为,实现更高级的功能。
总结来说,Vue 3 使用 Proxy 来实现响应式系统,相较于 Vue 2 的 Object.defineProperty,具有更好的性能和扩展性,并且可以监听新增和删除的属性。这些改进使得 Vue 3 的响应式系统更加强大和灵活。
例子:
假设我们有一个 Vue.js 2 的响应式对象 data
,它包含了两个属性 name
和 age
:
const data = {
name: 'John',
age: 25
}
在 Vue.js 2 中,如果我们将 data
对象传递给 Vue 实例进行响应式处理,Vue.js 会使用 Object.defineProperty
来劫持这两个属性的变化。
new Vue({
data: data
})
现在,如果我们在运行时向 data
对象中添加一个新的属性 gender
,Vue.js 2 将无法自动追踪和响应这个新增属性的变化。
data.gender = 'Male'
这是因为在初始化阶段,Vue.js 2 已经使用 Object.defineProperty
对 data
对象的 name
和 age
属性进行了劫持和监听,但它无法感知到后续的属性变化。
所以,当我们在运行时向 data
对象添加新的属性 gender
时,Vue.js 2 是无法自动将其变为响应式的,也无法触发相应的更新操作。
这就是为什么 Vue.js 2 无法监听新增属性的原因。它的响应式系统是在初始化阶段对属性进行劫持和监听的,而无法动态地追踪和响应后续的属性变化。这也是 Vue.js 3 引入 Proxy 对象的一个重要改进,它可以监听新增和删除的属性,提供了更强大和灵活的响应式能力。
组件实例
Vue 3 引入了组合式 API(setup),与 Vue 2 的选项式 API(各种生命周期data啥的) 相比,有以下几个主要区别:
-
组合式 API 的灵活性:组合式 API 允许开发者根据逻辑相关性来组织代码,而不是按照选项的方式将代码分散在不同的选项中。这样可以更好地组织和重用代码,使得代码更加可读和可维护。
-
组合式 API 的逻辑复用:组合式 API 提供了一种更好的逻辑复用方式,通过自定义组合函数,可以将逻辑相关的代码封装为一个可复用的组合函数,并在多个组件中进行复用。这使得代码的复用性更高,减少了重复编写相似逻辑的工作。
-
组合式 API 的类型推导:Vue 3 的组合式 API 借助 TypeScript 的类型推导能力,提供了更好的类型支持。开发者可以在组合函数中明确指定参数和返回值的类型,提供更好的代码提示和类型检查。
-
组合式 API 的逻辑封装:组合式 API 允许将逻辑封装在组合函数中,使得组件的代码更加简洁和聚焦。开发者可以将复杂的逻辑拆分成多个组合函数,每个组合函数负责不同的功能,从而提高代码的可读性和可维护性。
总的来说,组合式 API 提供了更灵活、可复用和可维护的方式来组织和编写代码。它使得开发者能够更好地组织逻辑、复用代码,并且提供了更好的类型支持。这些改进使得 Vue 3 的组合式 API 更适合开发大型复杂应用,并且提供了更好的开发体验。
生命周期
vue2:
beforeCreate:在实例初始化之后、数据观测 (data observer) 和事件配置之前被调用。
created:在实例创建完成后被调用,这时候实例已经完成了数据观测、属性和方法的运算,但是尚未挂载到 DOM 上。
beforeMount:在挂载开始之前被调用,相关的 render 函数首次被调用。
mounted:在挂载完成后被调用,此时组件已经被放入 DOM 中。
beforeUpdate:在组件更新之前被调用,发生在重新渲染之前。
updated:在组件更新之后被调用,发生在重新渲染之后。
beforeDestroy:在实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed:在实例销毁之后调用。此时,所有的指令都已解绑,所有的事件监听器都已移除。
vue3:
因为引入了组合式API,将组件逻辑转移到了setup函数中,setup函数就替代了beforeCreate和created勾子函数
onBeforeMount:在挂载之前执行的钩子函数。
onMounted:在组件挂载到 DOM 后执行的钩子函数。
onBeforeUpdate:在组件更新之前执行的钩子函数。
onUpdated:在组件更新后执行的钩子函数。
onBeforeUnmount:在组件卸载之前执行的钩子函数。
onUnmounted:在组件卸载后执行的钩子函数。
总结
-
响应式系统的性能优化:Vue 3 使用 Proxy 替代了 Vue 2 中的 Object.defineProperty,这使得响应式系统在性能上有所提升。Proxy 的实现方式更高效,可以一次性拦截整个对象或数组,而不需要逐个定义属性,从而提高了大型对象或数组的性能。
-
虚拟 DOM 的优化:Vue 3 在虚拟 DOM 的实现上进行了一些优化。它引入了静态树提升 (Static Tree Hoisting) 技术,可以在编译阶段检测到静态节点并将其提升为常量,减少了运行时的虚拟 DOM 操作,提高了渲染性能。
-
编译器的优化:Vue 3 的编译器进行了一些优化,生成的代码更加紧凑和高效。编译器在编译时会对模板进行静态分析,并生成更优化的渲染函数,减少了运行时的开销。
-
Tree-shaking 支持:Vue 3 的模块系统使用了 ES Module 的语法,使得现代的打包工具可以更好地进行 Tree-shaking,只打包使用到的组件和功能,减少了打包体积。