Vue3 數據劫持原理

/**
 * 響應式
 */
function reactive(target) {
  return createReactiveObject(target)
}

/**
 * 已代理過原始值與代理後的值 hashMap
 */

const rawToReactive = new WeakMap()
const reactiveToRaw = new WeakMap()

const effectStack=[]
/**
 * 創建響應式對象
 */
function createReactiveObject(target) {
  if (!isObject(target)) {
    return target
  }

  // 防止對象被重複代理
  let proxy = rawToReactive.get(target)
  if (proxy) {
    return proxy
  }

  // 防止代理又被代理
  if (reactiveToRaw.has(target)) {
    return target
  }

  let baseHandler = {
    get(target, key, receiver) {
      console.log('獲取')
      let res = Reflect.get(target, key, receiver)

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

      // res是當前獲取到的值
      return isObject(res) ? reactive(res) : res
    },
    set(target, key, value, receiver) {
      // console.log('設置')

      // 識別改屬性還是新增屬性
      let hasKey = hasOwn(target, key)
      let oldValue = target[key]
      if (!hasKey) {
        console.log('新增屬性')
      } else if (oldValue !== value) {
        console.log('修改屬性')
      }
      let res = Reflect.set(target, key, value, receiver)
      return res
    },
    deletePrototype(target, key) {
      console.log('刪除')
      let res = Reflect.deleteProperty(target, key)
      return res
    }
  }
  let observed = new Proxy(target, baseHandler) // proxy兼容性差
  rawToReactive.set(target, observed)
  reactiveToRaw.set(observed, target)
  return observed
}

/**
 * 判斷是否是對象
 */
function isObject(target) {
  return typeof target === 'object' && target !== null
}

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

let proxy = reactive({
  name: 'tom',
  age: {
    n: 300
  },
  children: [1, 2, 3, 4]
})

// proxy.name = 'jack'
proxy.age.n = 500 // 先獲取age 再設置n
// proxy.children.push(5)
console.log(proxy)

let arr = [1, 2, 3]
let proxy = reactive(arr)
proxy.push(4)
// 先添加元素4
// 再更改length
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章