[Предварительное исследование] Преимущества и сценарии использования прокси

JavaScript Vue.js

Люди, которые водят автомобили, часто не понимают устройства автомобиля, но глубокое понимание устройства автомобиля может оказать сильное влияние.

1. Введение

вместе сvue3.xвсе больше новостей,proxyдискуссии увеличиваются. относительноObject.defineProperty,proxyВ чем разница, в чем преимущества и где можно применить. Эта статья кратко знакомит

2.Object.defineProperty

разговариватьproxyПрежде, давайте рассмотримObject.defineProperty. каждый знает,vue2.xи предыдущие версии использовалиObject.definePropertyЧтобы добиться двусторонней привязки данных, как ее привязать? Вот простая реализация

function observer(obj) {
    if (typeof obj ==='object') {
        for (let key in obj) {
            if(obj.hasOwnProperty(key)){
                defineReactive(obj, key, obj[key])
            }
        }
    }
}

function defineReactive(obj, key, value) {
    //针对value是对象,递归检测
    observer(value)
    //劫持对象的key
    Object.defineProperty(obj, key, {
        get() {
            console.log('获取:'+key)
            return value
        },
        set(val) {
            //针对所设置的val是对象
            observer(val)
            console.log(key+"-数据改变了")
            value = val
        }
    })
}

let obj={
    name:'守候',
    flag:{
        book:{
            name:'js',
            page:325
        },
        interest:['火锅','旅游'],
    }
}

observer(obj)

в браузереconsoleВыполняйте, вроде работает нормально

Но на самом деле,Object.definePropertyПроблемы следующие

Проблема 1. Удаление или добавление свойств объекта не может быть отслежено

например, добавление атрибутаgender, с момента выполненияobserver(obj)Когда нет этого свойства, значит, за этим нельзя следить. Удаленные свойства также невозможно обнаружить

При добавлении атрибутовvueНужно использовать$setработать,$setтакже используется внутрьObject.definePropertyдействовать

Проблема 2. Изменения массива не отслеживаются

Как видно из приведенного выше рисунка, несмотря на то, что свойство массива на самом деле успешно изменено, его невозможно отследить.

Вопрос 3. Поскольку объект проходится рекурсивно, используйтеObject.definePropertyПерехват свойств объекта, если пройденный уровень объекта глубокий, это займет много времени, и могут быть даже проблемы с производительностью

3.proxy

дляproxy, описание на mdn: Объекты используются для определения пользовательского поведения для основных операций (таких как поиск свойств, назначение, перечисление, вызовы функций и т. д.)

Проще говоря, вы можете установить слой перехвата на целевой объект. Независимо от того, какая операция выполняется над целевым объектом, он должен пройти этот уровень перехвата.

это звучит как,proxyСравниватьObject.definePropertyЛегко в использовании и намного проще, на самом деле, это случай. Следующий тест, проводимый по указанному вышеуказанному коду, переписан прокси

function observerProxy(obj){
    let handler = {
      get (target, key, receiver) {
        console.log('获取:'+key)
        // 如果是对象,就递归添加 proxy 拦截
        if (typeof target[key] === 'object' && target[key] !== null) {
          return new Proxy(target[key], handler)
        }
        return Reflect.get(target, key, receiver)
      },
      set (target, key, value, receiver) {
        console.log(key+"-数据改变了")
        return Reflect.set(target, key, value, receiver)
      }
    }
    return new Proxy(obj, handler)
}


let obj={
    name:'守候',
    flag:{
        book:{
            name:'js',
            page:325
        },
        interest:['火锅','旅游'],
    }
}

let objTest=observerProxy(obj)

тот же эффект

Более того, это можно сделатьObject.definePropertyВещи, которые не могут быть сделаны, такие как добавление атрибутаgender, может контролировать

Манипулировать массивами, вы также можете контролировать

Наконец, постучите по доске и кратко изложите разницу между двумя

1.Object.definePropertyПерехват свойств объекта, изменение исходного объекта.proxyОн перехватывает весь объект и генерирует новый объект через новый без изменения исходного объекта.

2.proxyВ дополнение к вышеперечисленным методам получения и установки существует 11 методов перехвата. Есть много способов выбратьProxy, вы также можете отслеживать некоторыеObject.definePropertyОперации, которые невозможно контролировать, например, мониторинг массивов, мониторинг добавления и удаления свойств объекта и т. д.

4. сценарии использования прокси

оproxyСценарии использования , ограничены пространством, вот лишь несколько, можно переместить большеmdn.

см. здесь, разницу между двумя, иproxyПреимущества уже известны. Но в разработке, какие сценарии можно использоватьproxyНу вот список возможных ситуаций

4-1 Массивы отрицательных индексов

В использованииsplice(-1),slice(-1)При ожидании API, когда вводится отрицательное число, он находит последний элемент массива, но в обычном массиве отрицательные числа использовать нельзя.[1,2,3][-1]Этот код не выводит 3 . Чтобы сделать приведенный выше вывод кода 3 , вы также можете использоватьproxyвыполнить.

let ecArrayProxy = {
  get (target, key, receiver) {
    let _index=key<0?target.length+Number(key):key
    return Reflect.get(target, _index, receiver)
  }
}
let arr=new Proxy([1,2,3],ecArrayProxy)

4-2. Проверка формы

При изменении значения формы вы можетеsetОн перехватывается внутри, чтобы определить, является ли значение законным

let ecValidate = {
  set (target, key, value, receiver) {
    if (key === 'age') {
      //如果值小于0,或者不是正整数
      if (value<0||!Number.isInteger(value)) {
        throw new TypeError('请输入正确的年龄');
      }
    }
    return Reflect.set(target, key, value, receiver)
  }
}

let obj=new Proxy({age:18},ecValidate)
obj.age=16
obj.age='少年'

4-3. Добавьте дополнительные атрибуты

Например, требуется гарантировать, что после того, как пользователь введет правильный идентификационный номер, к информации о пользователе будут добавлены дата рождения, место происхождения и пол.

Как мы все знаем, первая и вторая цифры идентификационного номера представляют провинцию (автономный район, муниципалитет центрального подчинения, особый административный район), а третья и четвертая цифры представляют город (город уровня префектуры, автономная префектура). , лига и муниципалитет, находящиеся в прямом подчинении центрального правительства) Краткое изложение кодекса округов и округов). Цифры с седьмой по четырнадцатую – это дата рождения. Нижние 17 цифр представляют пол, мужские одиночные и женские парные.

const PROVINCE_NUMBER={
    44:'广东省',
    46:'海南省'
}
const CITY_NUMBER={
    4401:'广州市',
    4601:'海口市'
}

let ecCardNumber = {
  set (target, key, value, receiver) {
    if(key === 'cardNumber'){
        Reflect.set(target, 'hometown', PROVINCE_NUMBER[value.substr(0,2)]+CITY_NUMBER[value.substr(0,4)], receiver)
        Reflect.set(target, 'date', value.substr(6,8), receiver)
        Reflect.set(target, 'gender', value.substr(-2,1)%2===1?'男':'女', receiver)
    }
    return Reflect.set(target, key, value, receiver)
  }
}
let obj=new Proxy({cardNumber:''},ecCardNumber)

4-4 Форматирование данных

Например, есть требование передать временную метку на серверную часть, но веб-интерфейс получает строку времени, которую также можно использовать.proxyПерехват, когда строка времени получена, метка времени может быть добавлена ​​автоматически.

let ecDate = {
  set (target, key, value, receiver) {
    if(key === 'date'){
        Reflect.set(target, 'timeStamp', +new Date(value), receiver)
    }
    return Reflect.set(target, key, value, receiver)
  }
}
let obj=new Proxy({date:''},ecDate)

Ссылка на ссылку

Proxy

Интервьюер: Каковы преимущества и недостатки реализации прокси с двусторонней привязкой по сравнению с определением свойства?

Простое и популярное понимание прокси в Vue3.0

резюме

proxyа такжеObject.definepropertyнекоторые отличия иproxyЗдесь кратко представлены преимущества и сценарии использования. Эта статья не очень глубокая, и ее не сложно понять. Что касается прокси, то автор также намерен продолжить углубленное изучение, и если в будущем будет какой-либо выигрыш, я поделюсь им как можно скорее. Если в статье есть какие-либо ошибки или у вас есть какие-либо предложения, пожалуйста, оставьте сообщение в области комментариев.

------------------------- Великолепная разделительная линия --------------------

Если вы хотите узнать больше и пообщаться со мной, добавьте меня в WeChat. Или обратите внимание на мой паблик WeChat: В ожидании книжного магазина