vue.js设计与实现2 建立简单的响应式系统

建立简单的响应式系统

1.初始响应式数据与副作用函数

在vue.js中,假设我有一个文字节点,以来于一个字符串的变量,每当我修改这一个变量本身,那么这个文字节点在稍后也会改变。其实这一个机制就是依赖于vue的响应式系统,这个被依赖的变量称为响应式数据。而更新文字节点的函数其实就是其副作用函数。副作用函数本身,其实就是会产生副作用的函数:

 // 全局变量
 let val = 1

 function effect() {
   val = 2 // 修改全局变量,产生副作用
 }

假设这里有一个副作用函数,是修改body的innerText属性:

 const obj = { text: 'hello world' }
 function effect() {
   // effect 函数的执行会读取 obj.text
   document.body.innerText = obj.text
 }

那么对于响应式数据的话,我们希望每一次obj的text属性修改时,effect函数就会触发。

2.响应式数据的初步实现

1.观察上边代码

  • 其实每一次访问obj.text字段,例如effect函数,那么每一次都会触发读操作
  • 每一次修改obj.text字段,那么每一次都会触发设置的操作哦

2.从期望功能来看

我们希望,在effect函数执行之后,effect函数和obj.text字段就关联起来,每一次text修改我们都希望能够触发一次effect函数。
那么我们可以设置一个函数桶,在第一次执行effect函数之后,effect就会被存入函数桶里。
vue.js设计与实现2 建立简单的响应式系统_第1张图片
当text字段变化时,我们就会去访问函数桶,取出函数桶里边的函数,并执行
vue.js设计与实现2 建立简单的响应式系统_第2张图片

3.实现

现在,关键在于拦截对象的属性的读写操作,在ES2015 之前,只能通过 Object.defineProperty 函数实现,这也是 Vue.js 2 所采用的方式。在 ES2015+ 中,我们可以使用代理对象 Proxy 来实现,这也是 Vue.js 3 所采用的方式。

 // 存储副作用函数的桶
 const bucket = new Set()

 // 原始数据
 const data = { text: 'hello world' }
 // 对原始数据的代理
 const obj = new Proxy(data, {
   // 拦截读取操作
   get(target, key) {
     // 将副作用函数 effect 添加到存储副作用函数的桶中
     bucket.add(effect)
     // 返回属性值
     return target[key]
   },
   // 拦截设置操作
   set(target, key, newVal) {
     // 设置属性值
     target[key] = newVal
     // 把副作用函数从桶里取出并执行
     bucket.forEach(fn => fn())
     // 返回 true 代表设置操作成功
     return true
   }
 })

目前设置的这个系统,其实有不少缺陷,例如,它只能绑定一个字段,以及函数桶不能支持匿名函数,以及副作用函数希望可以脱离这种硬编码的方式,更加灵活多变。

你可能感兴趣的:(vue.js设计与实现笔记,vue.js,笔记,前端)