Чтобы изучить Vue3.0, давайте сначала разберемся с прокси

JavaScript Vue.js

Менеджеры по продукту проходят мимо, и изменения спроса не могут ускользнуть. Сестра-испытатель прищурилась и улыбнулась, сегодня вечером должно быть много жуков.

Сообщается, чтоVue3.0Официальная версия будет выпущена в этом месяце (август).Пройдет определенный переходный период от релиза до официальной инвестиции в официальный проект, но мы не можем дождаться, когдаVue3Учитесь только тогда, когда вы официально инвестируете в проект, учитесь заранее, чтобы быстрее его освоитьVue3.0, Это зависит от продвижения по службе и повышения зарплаты, чтобы выйти замуж за Бай Фумэй. но учусьVue3Перед этим нужно знатьProxy,этоVue3.0Основа для реализации двусторонней привязки данных.

Все вопросы в этой статье были впервые опубликованы на официальном аккаунте [Некоторые играют на фронтенде]. Редактор будет организовывать один или два вопроса для интервью каждый день, а затем рассылать их всем друзьям. Следуйте за редактором и отведите вас на чистку интервью вопросы каждый день Я не хочу быть соленой рыбой. , Хотите сменить работу, что вы все еще колеблетесь, обратите внимание на === большое заводское предложение. В то же время нажмите на ссылку ниже, чтобы прочитать высокопоставленную статью редактора и вместе изучить Vue.

Практические навыки, Vue тоже умеет так писать2800+ лайков

Абсолютно сухой материал~! Изучите эти советы Vue, вы сможете уйти с работы пораньше и встречаться с богиней1300+ лайков

Я настраиваю Vue в проекте так1200+ лайков

Впереди высокая энергия, это последняя волна боевых навыков Vue, это бесполезно и потрясающе.1100+ лайков

Научись пользоваться Vue JSX, машина старых крестных твоя800+ лайков

Понимание шаблонов прокси

один пример

Как одинокий стальной гетеросексуальный программист, Сяо Ван постепенно влюбился в девушку, работающую с интерфейсом, однако он не знаком с девушкой, поэтому он решил доверить девушку, которая знакома с интерфейсом. фронтовая девушка.UIДама помогла навести повод для себя. Так пожалуйстаUIМаленькая сестра плотно поела, а затем достала любовное письмо и доверила его маленькой девочке на стойке регистрации.我喜欢你,我想和你睡觉, достойный прямого человека из стали. Но точно бесполезно так писать.UIМисс и сестра едят короткие рты людей, поэтому она помогла изменить любовное письмо и изменила его на我喜欢你,我想和你一起在晨辉的沐浴下起床, а затем передал его маленькой девочке на стойке регистрации. Хотя неясно, был ли матч успешным, но эта история говорит нам о том, что Сяо Ван заслуживает того, чтобы быть холостым.

На самом деле вышеприведенный пример типичной модели агентства Сяо Ван хотел отправить любовное письмо девушке на стойке регистрации, но доверил ему, потому что не был знаком с этим.UI小姐姐,UIДевушка приравнивается к агенту, завершающему отправку любовных писем от имени Сяо Вана.

расширение

В приведенном выше примере мы думаемVueПринцип ответа данных, такой как следующий код

const xiaowang = {
  love: '我喜欢你,我想和你睡觉'
}
// 送给小姐姐情书
function sendToMyLove(obj) {
	console.log(obj.love)
	return '流氓,滚'
}
console.log(sendToMyLove(xiaowang))

если нетUIВместо этого юная леди отправила любовное письмо, показав, что финал был трагичен, подумайте об этом.Vue2.0двусторонняя привязка черезObject.definePropertyсвойства для прослушиванияget,setметод для достижения двусторонней привязки, этоObject.definePropertyэквивалентноUIМисс

const xiaowang = {
  loveLetter: '我喜欢你,我想和你睡觉'
}
// UI小姐姐代理
Object.defineProperty(xiaowang,'love', {
  get() {
    return xiaowang.loveLetter.replace('睡觉','一起在晨辉的沐浴下起床')
  }
})

// 送给小姐姐情书
function sendToMyLove(obj) {
	console.log(obj.love)
	return '小伙子还挺有诗情画意的么,不过老娘不喜欢,滚'
}
console.log(sendToMyLove(xiaowang))

Тем не менее, это все еще трагическая история, потому что вероятность успеха отправки Mercedes-Benz может быть немного выше. Но мы можем видеть это поObject.definepropertyВы можете перехватить существующие свойства объекта, а затем проделать некоторые дополнительные операции.

существующие проблемы

существуетVue2.0, двусторонняя привязка данных осуществляется черезObject.definePropertyпрослушивать каждое свойство объекта, а затем вget,setМетод реализует ответ данных через режим публикации-подписчика, но есть определенные недостатки, например, он может только мониторить существующие свойства, а добавлять и удалять свойства бессилен, а также не может отслеживать изменения массива. Следовательно, вVue3.0заменил его на более мощныйProxy.

Узнайте о прокси

ProxyдаES6Новая функция, которую можно использовать для перехватаjsметоды операций для выполнения прокси-операций над этими методами.

Перепишите приведенный выше пример с прокси

Например, мы можем пройтиProxyПереписывание сюжета любовного письма выше:

const xiaowang = {
  loveLetter: '我喜欢你,我想和你睡觉'
}
const proxy = new Proxy(xiaowang, {
  get(target,key) {
    if(key === 'loveLetter') {
      return target[key].replace('睡觉','一起在晨辉的沐浴下起床')
    }
  }
})
// 送给小姐姐情书
function sendToMyLove(obj) {
	console.log(obj.loveLetter)
	return '小伙子还挺有诗情画意的么,不过老娘不喜欢,滚'
}
console.log(sendToMyLove(proxy))

Посмотрите на эту сцену еще раз

Пожалуйста, используйте отдельноObject.definePropertyиProxyЗавершите следующую логику кода.

function observe(obj, callback) {}

const obj = observe(
  {
    name: '子君',
    sex: '男'
  },
  (key, value) => {
    console.log(`属性[${key}]的值被修改为[${value}]`)
  }
)

// 这段代码执行后,输出 属性[name]的值被修改为[妹纸]
obj.name = '妹纸'

// 这段代码执行后,输出 属性[sex]的值被修改为[女]
obj.sex = '女'

Прочитав приведенный выше код, я надеюсь, что вы сможете сначала реализовать следующее самостоятельно, давайте использоватьObject.definePropertyиProxyдля реализации вышеуказанной логики.

  1. использоватьObject.defineProperty
/**
 * 请实现这个函数,使下面的代码逻辑正常运行
 * @param {*} obj 对象
 * @param {*} callback 回调函数
 */
function observe(obj, callback) {
  const newObj = {}
  Object.keys(obj).forEach(key => {
    Object.defineProperty(newObj, key, {
      configurable: true,
      enumerable: true,
      get() {
        return obj[key]
      },
      // 当属性的值被修改时,会调用set,这时候就可以在set里面调用回调函数
      set(newVal) {
        obj[key] = newVal
        callback(key, newVal)
      }
    })
  })
  return newObj
}

const obj = observe(
  {
    name: '子君',
    sex: '男'
  },
  (key, value) => {
    console.log(`属性[${key}]的值被修改为[${value}]`)
  }
)

// 这段代码执行后,输出 属性[name]的值被修改为[妹纸]
obj.name = '妹纸'

// 这段代码执行后,输出 属性[sex]的值被修改为[女]
obj.name = '女'

  1. использоватьProxy
function observe(obj, callback) {
  return new Proxy(obj, {
    get(target, key) {
      return target[key]
    },
    set(target, key, value) {
      target[key] = value
      callback(key, value)
    }
  })
}

const obj = observe(
  {
    name: '子君',
    sex: '男'
  },
  (key, value) => {
    console.log(`属性[${key}]的值被修改为[${value}]`)
  }
)

// 这段代码执行后,输出 属性[name]的值被修改为[妹纸]
obj.name = '妹纸'

// 这段代码执行后,输出 属性[sex]的值被修改为[女]
obj.name = '女'

Благодаря двум вышеупомянутым различным методам реализации мы можем примерно понятьObject.definePropertyиProxyИспользование , но при добавлении новых свойств к объекту появляется разница, например

// 添加公众号字段
obj.gzh = '前端有的玩'

использоватьObject.definePropertyНевозможно отслеживать новые свойства, но используйтеProxyможно контролировать. Сравнив два приведенных выше фрагмента кода, можно обнаружить следующие отличия

  • Object.definePropertyОтслеживается каждое свойство объекта, иProxyМонитор — это сам объект
  • использоватьObject.definePropertyОн должен пройти через каждое свойство объекта, что окажет определенное влияние на производительность.
  • ProxyНовые свойства также можно отслеживать, ноObject.definePropertyНевозможно контролировать.

первое знакомствоProxy

Понятия и грамматика

существуетMDNпримерноProxyВводится так:ProxyОбъекты используются для определения пользовательского поведения для основных операций (таких как поиск свойств, присвоение, перечисление, вызовы функций и т. д.). Что это обозначает?ProxyКак и перехватчик, он может считывать свойства объекта, изменять свойства объекта, получать список свойств объекта черезfor inПри зацикливании и т. д. перехватите поведение по умолчанию для объекта, а затем настройте эти поведения самостоятельно, например, в приведенном выше примере.set, мы перехватываем значение по умолчаниюset, то в обычаеsetОн добавляет вызов функции обратного вызова

ProxyСинтаксис выглядит следующим образом

/**
* target: 要兼容的对象,可以是一个对象,数组,函数等等
* handler: 是一个对象,里面包含了可以监听这个对象的行为函数,比如上面例子里面的`get`与`set`
* 同时会返回一个新的对象proxy, 为了能够触发handler里面的函数,必须要使用返回值去进行其他操作,比如修改值
*/
const proxy = new Proxy(target, handler)

В приведенном выше примере мы использовалиhandlerпредоставлено вgetиsetМетод, давайте рассмотрим его один за другимhandlerметод внутри.

Список методов в обработчике

handlerМетоды внутри могут иметь следующие тринадцать, каждый из которых соответствует одному или несколькимproxyПоведение прокси-объектов

  1. handler.get

    когда прошелproxyКогда вы читаете свойства объекта, вы вводитеgetвнутри функции хука

  2. handler.set

    когда прошелproxyКогда вы перейдете к установке и изменению свойств объекта, вы войдете вsetвнутри функции хука

  3. handler.has

    когда используешьinОпределить, находится ли недвижимость вproxyНаходясь внутри прокси-объекта, он сработаетhas,Например

    const obj = {
      name: '子君'
    }
    console.log('name' in obj)
    
  4. handler.deleteProperty

    когда используешьdeleteПри удалении свойства в объекте оно войдет в хук-функцию deleteProperty`

  5. handler.apply

    когдаproxyКогда слушатель является функцией, когда функция вызывается, она войдетapplyфункция ловушки

  6. handle.ownKeys

    когда прошелObject.getOwnPropertyNames,Object.getownPropertySymbols,Object.keys,Reflect.ownKeysКогда вы пойдете, чтобы получить информацию об объекте, вы войдетеownKeysэта функция ловушки

  7. handler.construct

    когда используешьnewоператор, он войдетconstructэта функция ловушки

  8. handler.defineProperty

    когда используешьObject.definePropertyКогда вы измените модификатор атрибута, вы войдете в эту функцию ловушки

  9. handler.getPrototypeOf

    При чтении прототипа объекта он войдет в эту функцию хука

  10. handler.setPrototypeOf

    Когда прототип объекта установлен, он войдет в эту функцию ловушки.

  11. handler.isExtensible

    когда прошелObject.isExtensibleПри оценке того, может ли объект добавлять новые свойства, введите эту функцию ловушки

  12. handler.preventExtensions

    когда прошелObject.preventExtensionsЧтобы установить, что объект не может изменять новые свойства, введите эту функцию ловушки

  13. handler.getOwnPropertyDescriptor

    Эта операция запускается, когда получено описание свойства прокси-объекта, например, при выполненииObject.getOwnPropertyDescriptor(proxy, "foo")войдет в эту функцию ловушки, когда

ProxyПредусмотрено 13 методов перехвата операций с объектами, в этой статье в основном выбраны некоторые из них.Vue3Более важные из них объясняются, а остальные предложения можно прочитать непосредственноMDNоProxyвведение.

Подробное введение

get

когда прошелproxyКогда вы читаете свойства объекта, вы вводитеgetвнутри функции хука

когда мы идем отproxyКогда свойство читается на агенте, оно запускаетgetфункция крючка,getСтруктура функции следующая

/**
 * target: 目标对象,即通过proxy代理的对象
 * key: 要访问的属性名称
 * receiver: receiver相当于是我们要读取的属性的this,一般情况
 *           下他就是proxy对象本身,关于receiver的作用,后文将具体讲解
 */
handle.get(target,key, receiver)
Пример

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

// 状态码提示信息
const errorMessage = {
  400: '错误请求',
  401: '系统未授权,请重新登录',
  403: '拒绝访问',
  404: '请求失败,未找到该资源'
}

// 使用方式
const code = 404
const message = errorMessage[code]
console.log(message)

Но с этим есть проблема, существует много кодов состояния, мы не можем перечислить каждый код состояния, поэтому для некоторых аномальных кодов состояния мы надеемся, что сможем дать унифицированную подсказку, такую ​​как подсказка系统异常,请联系管理员, то вы можете использоватьProxyПрокси-обработка сообщений об ошибках

// 状态码提示信息
const errorMessage = {
  400: '错误请求',
  401: '系统未授权,请重新登录',
  403: '拒绝访问',
  404: '请求失败,未找到该资源'
}

const proxy = new Proxy(errorMessage, {
  get(target,key) {
    const value = target[key]
    return value || '系统异常,请联系管理员'
  }
})

// 输出 错误请求
console.log(proxy[400])
// 输出 系统异常,请联系管理员
console.log(proxy[500])

set

При присвоении значения свойству в объекте срабатываетset

При присвоении значения свойству в объекте срабатываетset,setСтруктура функции следующая

/**
 * target: 目标对象,即通过proxy代理的对象
 * key: 要赋值的属性名称
 * value: 目标属性要赋的新值
 * receiver: 与 get的receiver 基本一致
 */
handle.set(target,key,value, receiver)
Пример

Системе необходимо ввести ряд значений для статистики данных, но при вводе значений могут быть введены некоторые ненормальные значения, и эти ненормальные значения необходимо обрабатывать при вводе, например, больше чем100значение, преобразованное в100, меньше, чем0значение, преобразованное в0, то вы можете использоватьproxyизset, в момент присвоения данные обрабатываются

const numbers = []
const proxy = new Proxy(numbers, {
  set(target,key,value) {
    if(value < 0) {
      value = 0
    }else if(value > 100) {
      value = 100
    }
    target[key] = value
    // 对于set 来说,如果操作成功必须返回true, 否则会被视为失败
    return true
  }
})

proxy.push(1)
proxy.push(101)
proxy.push(-10)
// 输出 [1, 100, 0]
console.log(numbers)
В сравненииVue2.0

в настоящее время используетVue2.0При добавлении новых свойств к объекту часто необходимо вызвать$set, Это потому чтоObject.definePropertyМожно отслеживать только существующие свойства, а вновь добавленные свойства отслеживать нельзя.$setЭто эквивалентно ручному добавлению свойств к объекту и последующему запуску ответа данных. Но дляVue3.0, потому что с помощьюProxy, в егоsetНовые свойства можно отслеживать в функции ловушки, поэтому больше нет необходимости использовать$set

const obj = {
  name: '子君'
}
const proxy = new Proxy(obj, {
  set(target,key,value) {
    if(!target.hasOwnProperty(key)) {
      console.log(`新增了属性${key},值为${value}`)
    }
    target[key] = value
    return true
  }
})
// 新增 公众号 属性
// 输出 新增了属性gzh,值为前端有的玩
proxy.gzh = '前端有的玩'

has

когда используешьinОпределить, находится ли недвижимость вproxyНаходясь внутри прокси-объекта, он сработаетhas

/**
 * target: 目标对象,即通过proxy代理的对象
 * key: 要判断的key是否在target中
 */
 handle.has(target,key)
Пример

Обычно мыjsПри декларировании частной собственности в_В начале для этих приватных свойств нет необходимости во внешних вызовах, поэтому лучше всего, если это можно будет скрыть, тогда можно пройтиhasПри оценке того, находится ли свойство в объекте, если_начать, вернутьсяfalse

const obj =  {
  publicMethod() {},
  _privateMethod(){}
}
const proxy = new Proxy(obj, {
  has(target, key) {
    if(key.startsWith('_')) {
      return false
    }
    return Reflect.get(target,key)
  }
})

// 输出 false
console.log('_privateMethod' in proxy)

// 输出 true
console.log('publicMethod' in proxy)

deleteProperty

когда используешьdeleteПри удалении свойства в объекте оно попадет в перехватчик deleteProperty`

/**
 * target: 目标对象,即通过proxy代理的对象
 * key: 要删除的属性
 */
 handle.deleteProperty(target,key)
Пример

Теперь есть объект информации о пользователе, для некоторой информации о пользователе разрешен только просмотр, но не удаление или изменение, использованиеProxyВы можете перехватывать и создавать исключения для свойств, которые нельзя удалить или изменить, следующим образом.

const userInfo = {
  name: '子君',
  gzh: '前端有的玩',
  sex: '男',
  age: 22
}
// 只能删除用户名和公众号
const readonlyKeys = ['name', 'gzh']
const proxy = new Proxy(userInfo, {
  set(target,key,value) {
    if(readonlyKeys.includes(key)) {
      throw new Error(`属性${key}不能被修改`)
    }
    target[key] = value
    return true
  },
   deleteProperty(target,key) {
    if(readonlyKeys.includes(key)) {
      throw new Error(`属性${key}不能被删除`)
      return
    }
    delete target[key]
    return true
  }
})
// 报错 
delete proxy.name
В сравненииVue2.0

На самом деле с$setПроблема решена аналогично,Vue2.0Невозможно проконтролировать, что атрибут удален, поэтому он обеспечивает$deleteдля удаления атрибутов, но дляProxy, вы можете отслеживать операцию удаления, поэтому вам не нужно использовать ее снова$deleteохватывать

другие операции

Выше мы упоминалиProxyизhandlerПредусмотрено тринадцать функций. Мы перечислили три наиболее часто используемых выше. На самом деле, использование каждой из них в основном одинаково. Например.ownKeys, при прохождении черезObject.getOwnPropertyNames,Object.getownPropertySymbols,Object.keys,Reflect.ownKeysКогда вы пойдете, чтобы получить информацию об объекте, вы войдетеownKeysЭта функция ловушки, с помощью которой мы можем защитить некоторые свойства, которые мы не хотим раскрывать, например, общее соглашение._Те, что в начале, являются частными свойствами, поэтому при использованииObject.keysчтобы получить все объектыkey, можно поставить все_Атрибуты в начале замаскированы. Что касается остальных свойств, рекомендуется взглянутьMDNвведение в .

Reflect

В приведенном выше примере мы получаем значение атрибута или изменяем значение атрибута с помощью прямой операции.targetдобиться, а на самом делеES6предоставил намProxyПоведение объекта внутреннего вызова по умолчаниюAPI,которыйReflect. Например следующий код

const obj = {}
const proxy = new Proxy(obj, {
  get(target,key,receiver) {
    return Reflect.get(target,key,receiver)
  }
})

Вы можете увидеть приведенный выше код и использовать его напрямуюtarget[key]путь не имеет значения, но на практикеReflectказалось, позволяетObjectОписанная выше операция более стандартизирована, например, мы хотим судить об определенномpropНезависимо от того, находится ли он в объекте, он обычно используется дляin,который

const obj = {name: '子君'}
console.log('name' in obj)

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

Reflect.has(obj,'name')

Кромеhas,getКроме того, на самом делеReflectВсего выше предоставлено тринадцать статических методов, и эти тринадцать статических методов аналогичныProxyизhandlerВышеупомянутые тринадцать методов находятся во взаимно однозначном соответствии, комбинируяProxyиReflectВ совокупности операцию по умолчанию над объектом можно перехватить, конечно, это тоже относится к категории функционального метапрограммирования.

Суммировать

У некоторых студентов могут возникнуть сомнения, я не будуProxyиReflectя не могу учитьсяVue3.0Пока что? На самом деле, то, понимаете ли вы это, не влияет на обучение.Vue3.0Да, но если вы хотите понятьVue3.0, в этих еще надо разбираться. Например, люди часто используютVue2Когда я спросил, почему интерфейс не изменился после того, как я изменил значение массива через индекс? когда ты учишьсяObject.definePropertyПосле использования и ограничений вы вдруг поймете, что это так. После этой статьи редактор принесет вамVue3.0Серия статей, добро пожаловать, чтобы обратить внимание и учиться вместе. В то же время, эта статья была впервые опубликована в публичном аккаунте [Некоторые люди играют на фронтенде], и изучают фронтенд с позицией игры, как раз в [Некоторые люди играют на фронтенде].

Эпилог Не истощайте свое вдохновение и воображение, не будьте рабом своих моделей. - Винсент Ван Гог