С помощью сравнения перехвата данных Object.defineProperty узнайте, насколько хорош прокси-сервер.

JavaScript
С помощью сравнения перехвата данных Object.defineProperty узнайте, насколько хорош прокси-сервер.

предисловие

Прошло некоторое время с тех пор, как вышел vue3, и несомненно говорят, что перехват данных vue был переписан с прокси (ранее использовался Object.defineProperty) и Composition API. В этой статье давайте проверим, насколько хороша способность прокси к перехвату.

Сравнение перехвата данных Object.defineProperty и перехвата данных прокси

здесь черезvue1.x,vue2.xПоговорим о перехвате данныхObject.defineProperty.

Объясните заранее, перехват данных здесь не включает в себя сбор vue зависимостей и обновление представления, иначе его будут ругать милые друзья-копатели.

Object.defineProperty

использовать сначалаObject.definePropertyРеализовать перехват объекта.


let data = {
  m:234,
  n:[1,34,4,5676],
  h:{
    c:34
  }
}

function observer(data){
  if(typeof data === 'object'){
    Object.keys(data).forEach(key=>{
      defineReactive(data,key,data[key])
    })
  }
}

function defineReactive(obj,key,val){
  Object.defineProperty(obj,key,{
    get(){
      console.log('get')
      return val
    },
    set(newVal){
      console.log('set')
      if(newVal !== val ) val = newVal
    }
  })
}

выше, пересекаяdata, сделал простой перехват, вроде все нормально, но если мы изменимdata.h.cне сработаетset钩子的,Зачем? Потому что это еще не реализовано递归, так что только перехватил最表面的一层, который не заблокирован.

объект рекурсивного перехвата


function defineReactive(obj,key,val){
  observer(val)
  Object.defineProperty(obj,key,{
    get(){
      console.log('get')
      return val
    },
    set(newVal){
      console.log('set')
      if(newVal !== val ) val = newVal
    }
  })
}

Рекурсивный перехват, покаdefineReactive函数настройтесь сноваobserver函数Просто передайте ему значение, которое вы хотите перехватить. Таким образом реализуется многоуровневый перехват объектов. Но теперь массив не может быть перехвачен, когда мы вызываемpush,pop等方法это не сработаетset钩子的,Зачем? потому чтоObject.definePropertyПерехват массива вообще не поддерживается. Поскольку он его не поддерживает, мы можем перехватывать только эти('push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse')Как изменить свои данные.

Перехват массивов Object.defineProperty


function arrayMethods(){

  const arrProto = Array.prototype

  const arrayMethods = Object.create(arrProto)

  const methods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']

  methods.forEach(function (method) {

      const original = arrProto[method]

      Object.defineProperty(arrayMethods, method, {

          value: function v(...args) {
              console.log('set arrayMethods')
              return original.apply(this, args)

          }

      })

  })
  return arrayMethods
}

Вышеупомянутое перехватывает метод прототипа этих массивов, а затем перезаписывает прототип перехватываемого массива.Давайте просто изменим наблюдателя.


function observer(data){
  if(typeof data === 'object'){
    if(Array.isArray(data)){
      data.__proto__ = arrayMethods()
    }else{
      Object.keys(data).forEach(key=>{
        defineReactive(data,key,data[key])
      })
    }
  }
}

существуетvue, также будет судить оkeyУ вас есть__proto__, если нет, то поместите эти методы прямо на сам ключ, если есть, то прямо перезапишите этот__proto__.

полный код


function arrayMethods(){

  const arrProto = Array.prototype

  const arrayMethods = Object.create(arrProto)

  const methods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']

  methods.forEach(function (method) {

      const original = arrProto[method]

      Object.defineProperty(arrayMethods, method, {

          value: function v(...args) {
              console.log('set arrayMethods')
              return original.apply(this, args)

          }

      })

  })
  return arrayMethods
}

function observer(data){
  if(typeof data === 'object'){
    if(Array.isArray(data)){
      data.__proto__ = arrayMethods()
    }else{
      Object.keys(data).forEach(key=>{
        defineReactive(data,key,data[key])
      })
    }
  }
}

function defineReactive(obj,key,val){
  observer(val)
  Object.defineProperty(obj,key,{
    get(){
      console.log('get')
      return val
    },
    set(newVal){
      console.log('set')
      if(newVal !== val ) val = newVal
    }
  })
}

observer(data)

выше, это сделано对象和数组перехват(说明:vue2.x中的实现会比这里复杂,但大概思路和大概实现是这样), Казалось бы, трудно, в обмен на отличный результат довольно хорошо. Но действительно ли это то, что вы думаете? попробуй позвонитьdata.n[1] = xxx, он не запускаетсяset钩子的, который также находится вproxyДо появления он был бессилен, поэтому был предусмотрен во вуе$set,$deleteAPI.

Дебютный прокси-дебют

Я не буду вводить прокси здесь, просто примите это так, как вы его знаете. код напрямую

  let data = {
  m:234,
  n:[1,34,4,5676],
  h:{
    c:34
  }
}

function defineReactive(obj){
  Object.keys(obj).forEach((key) => {
    if(typeof obj[key] === 'object'){
      obj[key] = defineReactive(obj[key])
    }
  })
  return new Proxy(obj,{
    get(target,key){
      console.log('get')
      return target[key]
    },
    set(target,key,val){
      console.log('set')
      return target[key] = val
    }
  })
}

 data = defineReactive(data)

Просто немного кода, чтобы сделать это对象和数组перехват(说明:这里不是vue3的实现方法,vue3怎么实现的,我还不知道,还没看过它的源码,有兴趣自己去看一下,然后顺便告诉我一下怎么实现的,哈哈哈),Object.definePropertyЧего нельзя достичь, того можно достичь;Object.definePropertyЭто можно сделать, и это можно сделать. все, что вы настраиваетеpush,pop等方法Он может перехватить, вы регулируетеdata.n[1] = xxxЕго также можно перехватить, так что не будьте слишком круты Реализация этих двух версий дает мне личное ощущение, что это корейская красная версия (более мясистые и короткие ноги), версия Дилиреба (стройные и длинные ноги), хахаха, на мой вкус.

наконец

здесь только что对象和数组чтобы испытать силу прокси; прокси может сделать гораздо больше.

Если вы хотите узнать больше о возможностях прокси и других вариантах использования, вы можете прочитать две статьи выше (прочитайте, пожалуйста, добровольно, я не хочу ругать, говорить рекламу, рекомендовать слепые jbs и т. д., 🐶 спасите свою жизнь) .