vue2/vue3数据双向绑定原理对比

173 阅读2分钟

vue2: Object.defineProperty

vue2中的响应式核心是es5的Object.defineProperty,Object.defineProperty()方法会直接在一个对象上定义一个新的属性,或者修改其现有属性,并返回此对象。

当我们把一个普通的 JavaScript 对象传入 Vue 实例作为 data选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter,这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。

每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖 (render=>Touch=>getter=>Collect as Dependency=>Watcher)。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染 (setter=>Notify=>Watcher=>Trigger re-render=>Component Render Function)

image.png

当data属性是对象/数组的时候,每一次数据变更,我们都不得不遍历对象/数组,对象一般属性不多,遍历对于性能的消耗并不多,但是如果是数组,数组的元素可能成千上万,每一次数据变更都触发遍历,其带来的性能损耗太大,所以vue2对于对象响应式采用递归遍历实现,而对于数组,选择重写数组原型。

综上所述:vue2利用Object.defineProperty()为核心实现响应式有以下缺陷:

1.深度监听需要递归到底,耗费性能

2.vue组件实例载入的时候,data里的所有属性都被vue遍历并利用Object.defineProperty()把所有属性转换为getter/setter实现响应式,如果是后来添加的属性,没有getter与setter是无法实现响应式的,需要使用set()方法单独生成getter/setter

3.遍历生成getter/setter对于元素数目庞大的数组来说,性能损耗过大,所以vue不支持原生数组监听,选择重写数组原型。

proxy