精读《Vuejs设计与实现》(13)之响应系统3

134 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情

4.2响应式数据的基本实现

接着上文,如何让一个数据变为响应式数数据呢,我们吧响应式数据拆分成这两个过程

  • 当副作用函数执行时,触发变量的读取
  • 修改变量时,触发相应的操作

也就是说,要实现一个响应式变量,我们应当先能拦截到变量的读取和修改

image.png 同样,当我们修改变量时,这个流程应当颠倒过来

image.png 首先,我们需要一个Set来存储effect,因为Set可以避免重复,同时我们定义一个原始值

const effects = new Set()
// 原始值
const data = {text:'hello'}

说到拦截读取和修改,大部分人第一反应Object.defineProperty,这也是vue2用的办法,这个方法虽然兼容性比较好,但也存在一些问题,想必熟悉vue2的你都很清楚了,但是这本书是vue3的,我们自然也要选择类似vue3的写法。

在ES6中,新增了Proxy,字面意思就是代理,功能就是代理对这个对象的任何操作。具体的API大家可以参考这个 阮一峰ES6-Proxy

接着上文,我们开始通过Proxy写一个响应式数据.

在读取的时候,我们收集副作用函数,当修改的时候,我们运行副作用函数。

const obj = new Proxy(data,{
    get(target,key){
        effects.add(effect)
        return target[key]
    },
    set(target,key,value){
     target[key] = value
     effect.forEach(fn=>fn())
     return true
    }
})

这样就简单的实现了响应式,我们可依在F12里这样简单的测试一下

function effect = ()=>{
 document.body.innerHTML = obj.text
}
effect()
setTimeout(()=>{obj.text='1234'},1000)

当然,这只是一个最简单demo,里面有很多问题,比如这里的effect函数是不能变成其他名字的,这就叫硬编码,当然时不可取。 下一篇里,我们会改掉这一点