1. Advantages of Proxy

  • The Proxy object implements property listening
  • Multiple levels of nesting, where the next-level properties are processed as they are accessed
  • The default listens for dynamically added properties
  • The deletion of the default listening property
  • The default listens for the index and length properties of the array
  • Can be used as a separate module

2. Simulation implementation of Vue3 responsive API

const isObject = (val) = >val ! = =null && typeof val === 'object'
const convert = (target) = > (isObject(target) ? reactive(target) : target)
const hasOwnProperty = Object.prototype.hasOwnProperty
const hasOwn = (target, key) = > hasOwnProperty.call(target, key)

2. Create an interceptor object handler and set get/set/deleteProperty 3. Return the Proxy object */
function reactive(target) {
  if(! isObject(target))return target

  const handler = {
    get(target, key, receiver) {
      // Collect dependencies
      track(target, key)
      const result = Reflect.get(target, key, receiver)
      return convert(result)
    },
    set(target, key, value, receiver) {
      const oldValue = Reflect.get(target, key, receiver)
      let result = true
      if(oldValue ! == value) { result =Reflect.set(target, key, value, receiver)
        // Trigger the update
        trigger(target, key)
      }
      return result
    },
    deleteProperty(target, key) {
      const hadKey = hasOwn(target, key)
      const result = Reflect.deleteProperty(target, key)
      if (hadKey && result) {
        // Trigger the update
        trigger(target, key)
      }
      return result
    },
  }

  return new Proxy(target, handler)
}

let activeEffect = null
function effect(callback) {
  activeEffect = callback
  callback() // Access responsive object properties to collect dependencies
  activeEffect = null
}

// Collect dependencies
let targetMap = new WeakMap(a)function track(target, key) {
  if(! activeEffect)return
  let depsMap = targetMap.get(target)
  if(! depsMap) { targetMap.set(target, (depsMap =new Map()))}let dep = depsMap.get(key)
  if(! dep) { depsMap.set(key, (dep =new Set()))
  }
  dep.add(activeEffect)
}

// Trigger the update
function trigger(target, key) {
  const depsMap = targetMap.get(target)
  if(! depsMap)return
  const dep = depsMap.get(key)
  if (dep) {
    dep.forEach((effect) = > {
      effect()
    })
  }
}

function ref(raw) {
  // Determine whether raw is an object created by ref, and return it if so
  if (isObject(raw) && raw.__v_isRef) {
    return
  }
  let value = convert(raw)
  const r = {
    __v_isRef: true.get value() {
      track(r, 'value')
      return value
    },
    set value(newValue) {
      if(newValue ! == value) { raw = newValue value = convert(raw) trigger(r,'value')}}}return r
}

function toRefs(proxy) {
  const ret = proxy instanceof Array ? new Array(proxy.length) : {}
  for (const key in proxy) {
    ret[key] = toProxyRef(proxy, key)
  }
  return ret
}

function toProxyRef(proxy, key) {
  const r = {
    __v_isRef: true.get value() {
      return proxy[key]
    },
    set value(newValue) {
      proxy[key] = newValue
    },
  }
  return r
}

// Calculate the property implementation
function computed(getter) {
  const result = ref()
  effect(() = > (result.value = getter()))
  return result
}

Copy the code