初识 VUE 响应式原理
作者:京东零售 吴静
自从 Vue 发布以来,就受到了广大开发人员的青睐,提到 Vue,我们首先想到的就是 Vue 的响应式系统,那响应式系统到底是怎么回事呢?接下来我就给大家简单介绍一下 Vue 中的响应式原理。
vue2 的响应式原理
尽管 Vue2 将于 2023 年 12 月 31 日停止维护,但是我们依然有很多项目是基于 Vue2.X 进行开发的,那么我们先简单看一看 Vue2.X 是基于什么实现的吧~
Object.defineProperty
Vue2 的响应式原理是基于对象的 defineProperty()方法进行开发的,那么这个方法有什么作用呢?MDN 是这样介绍的:**
object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
也就是说,我们可以通过对象的这个方法精确的添加或者修改对象的属性。每个对象都具有 get/set 属性,当访问 get 属性时,会调用 getter 方法,当对象的属性值被修改时,会调用 setter 方法,正式基于 getter 和 setter 方法,Vue 才可以利用 Object.defineProperty 来实现响应式系统。
Object.defineProperty 在 Vue 中的使用
在 vue 中,当把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 会遍历此对象的所有属性,并使用 object.defineProperty 将这些属性转为 getter/setter,
getter/setter 可以追踪依赖,在属性被访问的时候通知视图变更。
vue3 的响应式原理
vue2.0 很好的实现了数据的双向绑定,但是也遗留了一个很重要的问题:由于 Vue 会在初始化实例时将 property 转化为 getter/setter,所以,property 必须在 data 对象上先存在才能让 Vue 将其转换为响应式数据。那么对于新增加的对象、或者某些需要特殊操作的数组想要转换为响应式数据就需要使用 Vue.set 等方法。
Vue3 就很好的解决了这个问题。那么,Vue3 是如何解决的呢?让我们就一起看看吧~
Proxy
提到 Vue3 的数据拦截,我们首先要了解什么是 proxy?
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
原来,Vue3 用了 Proxy 代理代替了 Object.defineProperty 方法。同样的,在 proxy 中也有 get/set 方法,举个例子~
我们通过给每一个目标对象都建立一个对应的 Proxy 对象对其代理就可以弥补 Object.defineProperty 对于新增对象无法监听的缺陷。
简单设计一个 Vue3 的响应系统
实现一个简单的响应系统的思路:
•读取(get)时,将副作用函数入栈;
•设置(set)时,将副作用函数出栈,执行副作用函数。
执行匿名函数 fn 方法时,会触发响应式数据 obj.text 的读取操作,进而触发代理对象 Proxy 的 get 拦截函数:
到此,我们会发现,有一个疑问,我们怎样能保证修改一个属性之后触发的副作用函数是我预期想要触发的副作用函数呢?为了解决这个问题,我们还需要建立副作用函数与目标对象的联系:
我们仅需要用 WeakMap 代替 Set 数据结构:
修改 Proxy 对象:
这样,我们就实现了一个简易的响应系统。那么为什么要用 weakMap 而不是使用 Map 呢?就交给大家一起思考啦~
参考文献
《Vue.js 设计与实现_霍春阳》
《ECMAScript 6 入门》-阮一峰
版权声明: 本文为 InfoQ 作者【京东科技开发者】的原创文章。
原文链接:【http://xie.infoq.cn/article/118bc90c00b5b7b4faf3cd774】。文章转载请联系作者。
评论