2024.05.14

vue 响应式实现(2)

对象的拦截

  1. 创建一个 reactive.js 作为编写的实现
const proxyObj = reactive({
  a: 1,
  b: 2,
  c: {
    aa: 11,
    bb: 22
  }
})
function reactive(target) {  return new Proxy(target, {    get() {},    set() {}  }) }export { reactive }
  1. 涉及到多种拦截的操作,如get、set、add、delete等操作
import handle from './behover/index.js'
function reactive(target) {
   // get(){},set(){}  return new Proxy(target, handle)
}
export { reactive }
// behover/index.js
function get(){}function set(){}function deleteProperty(){}function ownKeys(){}export {    get,sex,}
  1. 在拦截的时候根据对象的读写需要 触发依赖收集和更新
// effect/track.js
/**
 *
 * @param traget 对象
 * @param type 操作类型 是get还是has等。
 * @param key
 */
export const track = (traget,type,key) => { //}
// effect/trigger.js
export const trigger = (traget,type,key) => {}
// 所以创建操作类型的枚举
// 分为读写
// constant/enum.js
    export const TrackOpTypes = {        GET: 'get',        HAS: 'has',        ITERATE: 'iterate'    }
    export const TriggerOpTypes = {        SET: 'set',        ADD: 'add',        DELETE: 'delete'    }
  1. 根据访问方式完善代码
// behover/index

// proxyObj.a
function get(target,key) {    trigger(target, TrackOpTypes.GET,, key)      return Reflect.get(target,key)  }
// proxyObj.a = 2
function set(target,key,value){    trigger(target,TriggerOpTypes.SET,key)      return Reflect.set(target,key,value)  }
// delete proxyObj.a
function deletePropery(target,key) {    trigger(target,TriggerOpTypes.DELETE,key)     return Reflect.deleteProperty(target,key) }

// 'a' in proxObj
function has(target,key){    track(target,TrackOpTypes,key)     return Reflect.has(target,key) }
  1. 通过调试发现一些没必要的依赖收集和更新,重新改造如下
// utils/utils.js
export function isObject(target) {  return typeof target === 'object' && target !== null}export function hasChanged(oldV, newV) {  return !Object.is(oldV, newV)}
// behover/index

// proxyObj.c.a
function get(target, key) {
  trigger(target, TrackOpTypes.GET, key)
  const result = Reflect.get(target, key)   if (isObject(result)) {    return reactive(result)   }  return result
}

// proxyObj.a = 2
function set(target, key, value) {
  // 是属性值的新增还是修改
  const type = target.hasOwnProperty(key) ? TriggerOpTypes.SET : TriggerOpTypes.ADD
  const oldValue = target[key]   const result = Reflect.set(target, key, value)
  // 是否发生改变 决定是否派发更新
  if (hasChanged(oldValue, value)) {    trigger(target, TriggerOpTypes.SET, key)   }  return result
}

// delete proxyObj.a
function deletePropery(target, key) {
  const result = Reflect.deleteProperty(target, key)
  // 存在该属性
  if (target.hasOwnProperty(key) && result) {    trigger(target, TriggerOpTypes.DELETE, key)   }  return result
}

// for (let key in proxyObj) {}
function ownKeys(target) {  track(target, TrackOpTypes.ITERATE)   return Reflect.ownKeys(target) }
  1. 做一些边界的判断
// reactive.js
import handle from './behover/index.js'
import { isObject } from './utils/utils.js'
const proxyMap = new WeakMap()  function reactive(target) {
    // 如果不是对象的话 直接返回
if(!isObject(target)) return target    return new Proxy(target, handle) }const proxy =  new Proxy(target, handle)
// 如果已经代理过了,返回代理对象,
if(proxyMap.has(target)){    return proxyMap.get(target) }
  return proxy
}

export { reactive }