在 Vue 中,我们经常需要监听数据的变化,以便在数据发生变化时执行相应的操作。Vue 提供了 watch
属性来实现这一功能,但是它的实现原理是什么呢?本文将深入探讨 Vue 监听数据对象变化的源码实现。
Object.defineProperty
要了解 Vue 监听数据对象变化的源码,首先需要了解 JavaScript 中的一个 API:Object.defineProperty
。这个 API 可以给一个对象定义一个属性,并在该属性的读取或赋值时执行相应的操作。例如:
----- --- - - ------ -------- --- ------ - ---------------- ------- ------ ----------- -- --- ----------- - ---------------- ---- ---- ------- ---------- - ------ - -- --------- -- -- ---- ----- - ------- -------- - ------ -- -- ---- ---- -- ----
可以看到,在访问和修改 obj
的 name
属性时,会自动执行 get
和 set
方法。
Vue 利用了 Object.defineProperty
来实现监听数据对象变化的功能。具体来说,Vue 在初始化时会遍历所有的数据对象,对其所有属性都调用 Object.defineProperty
,把每个属性的读取和赋值操作重写为自己定义的函数。这些函数在每次读取或赋值时会触发 Vue 内部相关的逻辑,从而实现了数据的监听和响应式更新。
Vue 的源码实现
下面我们来看一下 Vue 监听数据对象变化的源码实现。为了方便起见,我们只展示关键部分的代码。
Observer 类
Vue 中的 Observer
类用于对数据对象进行观察,并在数据发生变化时通知相关的订阅者。以下是 Observer
类中的主要方法:
----- -------- - ------------------ - ---------- - ------ -------- - --- ------ -- -- ----- ----------------------- -- ---------------------- - ---------------------------- -------------- ------------------------- - ---- - ----------------- - - -- -------------- ------- -- --------- - --- ------ --- -- ---- - ------------------- ----- - - -- --------------------- ----------------- - --- ---- - - -- - - ----------- ---- - ---------------- - - - -- -------------- -------- -------------- - -- ------- ----- --- -------- -- ----- --- ----- - ------- - --- --- -- -------------- - -- - ------------- - ---- - -- - --- ---------------- - ------ --- -
可以看到,Observer
类中的 walk
方法会遍历对象的每个属性,并调用 defineReactive
函数将其转换为 get/set 形式。observeArray
方法则是专门用于观察数组的元素。
defineReactive 函数
defineReactive
函数是 Vue 监听数据对象变化的核心。它接受一个对象和一个属性名作为参数,将该属性重写为一个 getter 和一个 setter,并且在该属性被读取或赋值时触发相应的逻辑。以下是 defineReactive
函数的代码:
-------- ------------------- ---- - ----- --- - --- ------ --- --- - --------- ----- ------ - ---------- - ------------- -- ------- ------ ---- -- ----- ------ - ---------------- - --- - ------- ------------- -- ------ ---------------------------------------------------------- ---------- -------------------------------------------------------------------------------------