zoukankan      html  css  js  c++  java
  • 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'
  • 相关阅读:
    pair<,>
    PTA 5-8 File Transfer (25)
    PTA 5-6 Root of AVL Tree (25)
    PTA 5-5 Tree Traversals Again (25)
    HDU4288 Coder(线段树)
    CodeForces 371D Vessels(树状数组)
    POJ2762 Going from u to v or from v to u(单连通 缩点)
    LightOJ 1030 Discovering Gold(期望 概率)
    HDU5115 Dire Wolf(区间DP)
    HDU4008 Parent and son(树形DP LCA)
  • 原文地址:https://www.cnblogs.com/lzq035/p/14643750.html
Copyright © 2011-2022 走看看