• Vue2/3响应式原理实现


    响应式原理

    1.什么是响应式

    监听对象中的属性被设置或获取的过程,当对象属性变化时能够监听到,并发出通知

    2.响应式函数的封装

    const reactiveFns = []
    watchFn(fn) {  }
    

    3.Depend 类的封装

    class Depend {
      constructor() {
        this.reactiveFns = []
      }
    
      addDepend(reactiveFn) {
        this.reactiveFns.push(reactiveFn)
      }
    
      notify() {
        this.reactiveFns.forEach(fn => {
          fn()
        })
      }
    }
    

    4. 监听对象的变化

    new Proxy(, set: depend.notify())
    

    5. 依赖收集的数据结构

    WeakMap

    function getDepend() {}
    

    6. 正确的收集依赖

    Proxy的get方法中收集对应的函数
    全局activeReactiveFn变量
    在get中找到depend对象, addDepend(全局activeReactiveFn变量)

    7. 对Depend进行优化

    addDepend函数换成depend函数
    直接获取到自由变量
    将之前保存的数组[]变成Set

    8. 对对象的响应式操作

    封装reactive函数

    • new Proxy(): Vue3
    • Object.defineProperty(): Vue2

    vue3响应式实现:

    // 保存当前需要收集的响应式函数
    let activeReactiveFn = null
    
    /**
     * Depend优化:
     *  1> depend方法
     *  2> 使用Set来保存依赖函数, 而不是数组[]
     */
    
    class Depend {
      constructor() {
        this.reactiveFns = new Set()
      }
    
      // addDepend(reactiveFn) {
      //   this.reactiveFns.add(reactiveFn)
      // }
    
      depend() {
        if (activeReactiveFn) {
          this.reactiveFns.add(activeReactiveFn)
        }
      }
    
      notify() {
        this.reactiveFns.forEach(fn => {
          fn()
        })
      }
    }
    
    // 封装一个响应式的函数
    function watchFn(fn) {
      activeReactiveFn = fn
      fn()
      activeReactiveFn = null
    }
    
    // 封装一个获取depend函数
    const targetMap = new WeakMap()
    function getDepend(target, key) {
      // 根据target对象获取map的过程
      let map = targetMap.get(target)
      if (!map) {
        map = new Map()
        targetMap.set(target, map)
      }
    
      // 根据key获取depend对象
      let depend = map.get(key)
      if (!depend) {
        depend = new Depend()
        map.set(key, depend)
      }
      return depend
    }
    
    function reactive(obj) {
      return new Proxy(obj, {
        get: function(target, key, receiver) {
          // 根据target.key获取对应的depend
          const depend = getDepend(target, key)
          // 给depend对象中添加响应函数
          // depend.addDepend(activeReactiveFn)
          depend.depend()
      
          return Reflect.get(target, key, receiver)
        },
        set: function(target, key, newValue, receiver) {
          Reflect.set(target, key, newValue, receiver)
          // depend.notify()
          const depend = getDepend(target, key)
          depend.notify()
        }
      })
    }
    
    // 监听对象的属性变量: Proxy(vue3)/Object.defineProperty(vue2)
    const objProxy = reactive({
      name: "why", // depend对象
      age: 18 // depend对象
    })
    
    const infoProxy = reactive({
      address: "广州市",
      height: 1.88
    })
    
    watchFn(() => {
      console.log(infoProxy.address)
    })
    
    infoProxy.address = "北京市"
    
    const foo = reactive({
      name: "foo"
    })
    
    watchFn(() => {
      console.log(foo.name)
    })
    
    foo.name = "bar"
    
    
    

    vue2响应式实现:

    // 保存当前需要收集的响应式函数
    let activeReactiveFn = null
    
    /**
     * Depend优化:
     *  1> depend方法
     *  2> 使用Set来保存依赖函数, 而不是数组[]
     */
    
    class Depend {
      constructor() {
        this.reactiveFns = new Set()
      }
    
      // addDepend(reactiveFn) {
      //   this.reactiveFns.add(reactiveFn)
      // }
    
      depend() {
        if (activeReactiveFn) {
          this.reactiveFns.add(activeReactiveFn)
        }
      }
    
      notify() {
        this.reactiveFns.forEach(fn => {
          fn()
        })
      }
    }
    
    // 封装一个响应式的函数
    function watchFn(fn) {
      activeReactiveFn = fn
      fn()
      activeReactiveFn = null
    }
    
    // 封装一个获取depend函数
    const targetMap = new WeakMap()
    function getDepend(target, key) {
      // 根据target对象获取map的过程
      let map = targetMap.get(target)
      if (!map) {
        map = new Map()
        targetMap.set(target, map)
      }
    
      // 根据key获取depend对象
      let depend = map.get(key)
      if (!depend) {
        depend = new Depend()
        map.set(key, depend)
      }
      return depend
    }
    
    function reactive(obj) {
      // {name: "why", age: 18}
      // ES6之前, 使用Object.defineProperty
      Object.keys(obj).forEach(key => {
        let value = obj[key]
        Object.defineProperty(obj, key, {
          get: function() {
            const depend = getDepend(obj, key)
            depend.depend()
            return value
          },
          set: function(newValue) {
            value = newValue
            const depend = getDepend(obj, key)
            depend.notify()
          }
        })
      })
      return obj
    }
    
    // 监听对象的属性变量: Proxy(vue3)/Object.defineProperty(vue2)
    const objProxy = reactive({
      name: "why", // depend对象
      age: 18 // depend对象
    })
    
    const infoProxy = reactive({
      address: "广州市",
      height: 1.88
    })
    
    watchFn(() => {
      console.log(infoProxy.address)
    })
    
    infoProxy.address = "北京市"
    
    const foo = reactive({
      name: "foo"
    })
    
    watchFn(() => {
      console.log(foo.name)
    })
    
    foo.name = "bar"
    foo.name = "hhh"
    
    
  • 相关阅读:
    EXCEL自动导出HTML
    亡灵序曲超清
    支持国产动画-唐伯卿和曾小兰
    中国表情
    logging 日志
    datetime库运用
    hashlib 加密
    os2
    python json数据处理
    python操作redis
  • 原文地址:https://www.cnblogs.com/axl234/p/16071957.html
Copyright © 2020-2023  润新知