vuejs设计与实现-4.1/4.2响应式数据与副作用函数

前题问题

1.什么是副作用函数?

  • 函数的执行导致函数作用域外的变量等发生变化,则该函数称作副作用函数

2.什么是响应式数据?

  • 当某个数据发生变化的时候,自动触发了副作用函数,可以成为这个数据为响应式数据
// 以下举例说明副作用函数和响应式数据
// 副作用函数
function effect(){
  document.body.innerText = data.text
}

// 响应式函数,可以将普通数据转为响应式数据
function reactive(obj){
  // .....
}

const data = reactive({text: 'hello world'})

// 修改数据
setTimeout(() => {
  // reactive对原始数据进行处理,此时这里的修改会自动触发effect函数执行
  data.text = 'hello vue3' 
}, 3000);


// 以上effect 函数执行会就会产生副作用,导致body标签内容发生变化,所以它就是副作用函数
// 定时器内对响应式数据进行了赋值,此时就是致使effect 函数再次执行,而为什么会导致effect执行,这就是后文要讨论的问题

响应式数据的基本实现

Vuejs2.x使用的是 Object.defineProperty 实现, Vuejs3.x 则是实用Proxy的实现方式

基本思路:

  • 将原始数据进行代理,实现 gettersetter 函数

  • 当执行副作用 effect 函数时,会触发对应数据的 getter 函数,此时将这个 effect 函数保存到容器 bucket 中,等待在未来某时刻执行

  • 当执行 data.text = xxx 操作时,会触发对应数据的 setter 函数,此时从容器 bucket 中取出所有 effect 函数并执行它们

  // 副作用函数
  function effect() {
    document.body.innerText = data.text
  }
	// 响应式函数
  function reactive(obj) {
    if (typeof obj !== 'object') {
      throw new Error('type error')
    }

    return new Proxy(obj, {
      get(target, key) {
        // 保存副作用函数 effect
        bucket.add(effect)
        return target[key]
      },
      set(target, key, value) {
        target[key] = value
				// 从容器 bucket 中取出 effect 函数并执行
        bucket.forEach(effect => effect())
        return true
      }
    })
  }

  const obj = { text: 'hello world' }
  // 存储副作用函数的容器
  const bucket = new Set()
  const data = reactive(obj)

  // 初始化执行,触发 getter 函数,收集 effect
  effect()

	// 3s 后触发setter 函数,触发副作用函数执行
  setTimeout(() => {
    data.text = 'hello vue3'
  }, 3000)

以上就是简单的一个响应式实现过程。但是整体仍有许多缺陷。

  • 副作用函数effect 硬编码,应该是哪怕副作用函数是匿名的,也能被正确的进行收集到容器中,从而在未来某个班时刻被执行
  • 所有的副作用函数都是一股脑全部塞进了Set数据结构的bucket中,副作用函数和被操作目标的字段之间无法建立明确的关系

基于以上等问题4.3节,实现一个完善的响应式系统

你可能感兴趣的:(vue.js,javascript,前端框架)