Vue3.0 简化版数据响应式原理

// vue3响应式原理:利用Proxy对象对数据拦截
const toProxy = new WeakMap() // 形如 obj: observed
const toRaw = new WeakMap() // 形如 observed: obj

function isObject(obj) {
  return typeof obj === 'object' && obj !== null
}

function hasOwn(obj, key) {
  return obj.hasOwnProperty(key)
}

function reactive(obj) {
  if (!isObject(obj)) {
    return obj
  }

  // 查找缓存
  if (toProxy.has(obj)) {
    return toProxy.get(obj)
  }
  // 传入obj就是代理对象,此时不用反复代理
  if (toRaw.has(obj)) {
    return obj
  }

  const observed = new Proxy(obj, {
    get(target, key, receiver) {
      // 访问
      const res = Reflect.get(target, key, receiver)
      console.log(`获取${key}: ${res}`)

      // 依赖收集
      track(target, key)

      return isObject(res) ? reactive(res) : res
    },
    set(target, key, value, receiver) {
      // 新增和更新
      const hadKey = hasOwn(target, key) // ADD 或 SET
      const oldVal = target[key]
      const res = Reflect.set(target, key, value, receiver)
      if (!hadKey) {
        console.log(`新增${key}:${value}`)
        trigger(target, 'ADD', key)
      } else if (oldVal !== value) {
        console.log(`设置${key}:${value}`)
        trigger(target, 'SET', key)
      }
      return res
    },
    deleteProperty(target, key) {
      // 删除
      const hadKey = hasOwn(target, key)
      const res = Reflect.deleteProperty(target, key)
      // key存在并且删除成功
      if (res && hadKey) {
        console.log(`删除${key}:${res}`)
        trigger(target, 'DELETE', key)
      }
      return res
    }
  })
  
  // 缓存
  toProxy.set(obj, observed)
  toRaw.set(observed, obj)

  return observed
}

const activeReativeEffectStack = []

// 依赖收集执行
// 基本结构{target:{key:[eff1,eff2]}}
let targetsMap = new WeakMap()

function track(target, key) {
  // 从栈中获取响应函数
  const effect = activeReativeEffectStack[activeReativeEffectStack.length - 1]
  if (effect) {
    let depsMap = targetsMap.get(target)
    if (!depsMap) {
      // 首次访问target
      depsMap = new Map()
      targetsMap.set(target, depsMap)
    }

    // 存放key
    let deps = depsMap.get(key)
    if (!deps) {
      deps = new Set()
      depsMap.set(key, deps)
    }
    if (!deps.has(effect)) {
      deps.add(effect)
    }
  }
}

function effect(fn) {
  // 1.异常处理
  // 2.执行函数
  // 3.放置到activeReativeEffectStack
  const rxEffect = function(...args) {
    try {
      activeReativeEffectStack.push(rxEffect)
      return fn(...args) // 执行函数触发依赖收集
    } finally {
      activeReativeEffectStack.pop()
    }  
  }

  rxEffect() // 默认立即执行
  return rxEffect
}


// 触发target.key对应响应函数
function trigger(target, type, key) {
  // 获取依赖表
  const depsMap = targetsMap.get(target)
  if (depsMap) {
    // 获取响应函数集合
    const deps = depsMap.get(key)
    const effects = new Set()
    if (deps) {
      // 执行所有响应函数
      deps.forEach(effect => {
        // effect()
        effects.add(effect)
      })
    }

    // 数组新增或删除
    if (type === 'ADD' || type === 'DELETE') {
      if (Array.isArray(target)) {
        const deps = depsMap.get('length')
        if (deps) {
          deps.forEach(effect => {
            effects.add(effect)
          })
        }
      }
    }
    // 获取已存在的Dep Set执行
    effects.forEach(effect => effect())
  }
}

const data = { foo: 'foo', bar: { a: 1 } }
const react = reactive(data)
// 1.获取
// react.foo // ok
// 2.设置已存在属性
// react.foo = 'foooooooo'
// 3.设置不存在属性
// react.baz = 'bazzzzzz'
// 4.嵌套对象
// react.bar.a = 10

// 避免重复代理
// console.log(reactive(data) === react) // true
// reactive(react)
effect(() => {
  console.log('数据发生了变化:', react.foo)
  // dom
})
react.foo = 'fooooooo'

  

// vue3响应式原理:利用Proxy对象对数据拦截
const toProxy = new WeakMap() // 形如 obj: observed
const toRaw = new WeakMap() // 形如 observed: obj

function isObject(obj) {
  return typeof obj === 'object' && obj !== null
}

function hasOwn(objkey) {
  return obj.hasOwnProperty(key)
}

function reactive(obj) {
  if (!isObject(obj)) {
    return obj
  }

  // 查找缓存
  if (toProxy.has(obj)) {
    return toProxy.get(obj)
  }
  // 传入obj就是代理对象,此时不用反复代理
  if (toRaw.has(obj)) {
    return obj
  }

  const observed = new Proxy(obj, {
    get(targetkeyreceiver) {
      // 访问
      const res = Reflect.get(targetkeyreceiver)
      console.log(`获取${key}${res}`)

      // 依赖收集
      track(targetkey)

      return isObject(res) ? reactive(res) : res
    },
    set(targetkeyvaluereceiver) {
      // 新增和更新
      const hadKey = hasOwn(targetkey// ADD 或 SET
      const oldVal = target[key]
      const res = Reflect.set(targetkeyvaluereceiver)
      if (!hadKey) {
        console.log(`新增${key}:${value}`)
        trigger(target'ADD'key)
      } else if (oldVal !== value) {
        console.log(`设置${key}:${value}`)
        trigger(target'SET'key)
      }
      return res
    },
    deleteProperty(targetkey) {
      // 删除
      const hadKey = hasOwn(targetkey)
      const res = Reflect.deleteProperty(targetkey)
      // key存在并且删除成功
      if (res && hadKey) {
        console.log(`删除${key}:${res}`)
        trigger(target'DELETE'key)
      }
      return res
    }
  })
  
  // 缓存
  toProxy.set(objobserved)
  toRaw.set(observedobj)

  return observed
}

const activeReativeEffectStack = []

// 依赖收集执行
// 基本结构{target:{key:[eff1,eff2]}}
let targetsMap = new WeakMap()

function track(targetkey) {
  // 从栈中获取响应函数
  const effect = activeReativeEffectStack[activeReativeEffectStack.length - 1]
  if (effect) {
    let depsMap = targetsMap.get(target)
    if (!depsMap) {
      // 首次访问target
      depsMap = new Map()
      targetsMap.set(targetdepsMap)
    }

    // 存放key
    let deps = depsMap.get(key)
    if (!deps) {
      deps = new Set()
      depsMap.set(keydeps)
    }
    if (!deps.has(effect)) {
      deps.add(effect)
    }
  }
}

function effect(fn) {
  // 1.异常处理
  // 2.执行函数
  // 3.放置到activeReativeEffectStack
  const rxEffect = function(...args) {
    try {
      activeReativeEffectStack.push(rxEffect)
      return fn(...args// 执行函数触发依赖收集
    } finally {
      activeReativeEffectStack.pop()
    }  
  }

  rxEffect() // 默认立即执行
  return rxEffect
}


// 触发target.key对应响应函数
function trigger(targettypekey) {
  // 获取依赖表
  const depsMap = targetsMap.get(target)
  if (depsMap) {
    // 获取响应函数集合
    const deps = depsMap.get(key)
    const effects = new Set()
    if (deps) {
      // 执行所有响应函数
      deps.forEach(effect => {
        // effect()
        effects.add(effect)
      })
    }

    // 数组新增或删除
    if (type === 'ADD' || type === 'DELETE') {
      if (Array.isArray(target)) {
        const deps = depsMap.get('length')
        if (deps) {
          deps.forEach(effect => {
            effects.add(effect)
          })
        }
      }
    }
    // 获取已存在的Dep Set执行
    effects.forEach(effect => effect())
  }
}

const data = { foo: 'foo'bar: { a: 1 } }
const react = reactive(data)
// 1.获取
// react.foo // ok
// 2.设置已存在属性
// react.foo = 'foooooooo'
// 3.设置不存在属性
// react.baz = 'bazzzzzz'
// 4.嵌套对象
// react.bar.a = 10

// 避免重复代理
// console.log(reactive(data) === react) // true
// reactive(react)
effect(() => {
  console.log('数据发生了变化:'react.foo)
  // dom
})
react.foo = 'fooooooo'
posted @ 2021-04-11 14:20  a权  阅读(123)  评论(0编辑  收藏  举报
Top