Прокси-объекты менеджера, модуля multiprocessing в Python
Что такое прокси-объект и как его использовать в процессах
Прокси-объекты создаются менеджерами процесса multiprocessing.Manager() .
Прокси-объект — это объект, который ссылается на общий объект, который (предположительно) живет в другом процессе. Общий объект называется референтом прокси. Один и тот же референт может иметь несколько прокси-объектов.
Прокси-объект имеет методы, которые вызывают соответствующие методы его референта, хотя не каждый метод референта обязательно будет доступен через прокси. Таким образом, прокси можно использовать так же, как и его референт:
>>> from multiprocessing import Manager >>> manager = Manager() >>> l = manager.list([i*i for i in range(10)]) >>> print(l) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> print(repr(l)) # >>> l[4] # 16 >>> l[2:5] # [4, 9, 16]
Обратите внимание, что применение функции str() к прокси вернет представление референта, тогда как применение [функции repr() вернет представление прокси.
Важная особенность прокси-объектов заключается в том, что они упаковываются модулем pickle , поэтому их можно передавать между процессами. Таким образом, референт может содержать прокси-объекты. Прокси-объектам разрешается иметь вложенные управляемые объекты: это относится к спискам, словарям и другим прокси-объектам:
>>> a = manager.list() >>> b = manager.list() >>> a.append(b) # референт `a` теперь содержит референт `b` >>> print(a, b) # [] [] >>> b.append('hello') >>> print(a[0], b) # ['hello'] ['hello']
Аналогично, прокси-объекты dict и list могут быть вложены друг в друга:
>>> l_outer = manager.list([ manager.dict() for i in range(2) ]) >>> d_first_inner = l_outer[0] >>> d_first_inner['a'] = 1 >>> d_first_inner['b'] = 2 >>> l_outer[1]['c'] = 3 >>> l_outer[1]['z'] = 26 >>> print(l_outer[0]) # >>> print(l_outer[1]) #
Если стандартный (не прокси) список list или словарь dict содержатся в референте, то изменения этих изменяемых значений не будут распространяться через менеджер, поскольку прокси не имеет возможности узнать, когда изменены содержащиеся в нем значения.
Однако сохранение значения в прокси-объекте контейнера (которое запускает __setitem__ на объекте-прокси) распространяется через менеджер, поэтому для эффективного изменения такого элемента можно повторно назначить измененное значение прокси-объекту контейнера:
# создаем прокси-объект списка и добавляем # изменяемый объект (словарь) lproxy = manager.list() lproxy.append(<>) # теперь изменяем словарь d = lproxy[0] d['a'] = 1 d['b'] = 2 # на данный момент изменения в словаре `d` еще не # синхронизированы, но при переназначении словаря # прокси-сервер получает уведомление об этом изменении lproxy[0] = d # теперь изменения распространены на все процессы
Этот подход, для большинства случаев использования, менее удобен, чем использование вложенных прокси-объектов, но он демонстрирует уровень контроля над синхронизацией.
Примечание. Типы прокси в модуле multiprocessing ничего не делают для поддержки сравнения по значению.
Так, например есть:
>>> manager.list([1,2,3]) == [1,2,3] # False
Вместо этого следует просто использовать копию референта при проведении сравнений.
что такое Proxy Object?
Hibernate автоматически генерирует для ваших классов с данными наследников, которые перехватывают get-методы для реализации ленивой загрузки и set-методы для отслеживания изменений.
Эти классы называются proxy-классами, а их экземпляры — proxy-объектами.
Отслеживать
ответ дан 21 сен 2018 в 10:53
Pavel Mayorov Pavel Mayorov
58.5k 7 7 золотых знаков 72 72 серебряных знака 146 146 бронзовых знаков
В общем случае прокси-объект — это объект, который служит посредником для доступа к другому объекту, каким-то образом меняя свойства или поведение этого объекта.
Так что со стороны клиента (т.е. объекта-пользователя) поведение выглядит несколько не так, как было бы при непосредственном доступе.
Используется также в случаях, когда прямой доступ к используемому объекту по какой-то причине невозможен. См. подробнее:
Отслеживать
ответ дан 21 сен 2018 в 10:10
3,377 10 10 серебряных знаков 24 24 бронзовых знака
- java
- hibernate
- jpa
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.4.3.7257
Что такое прокси-объекты?
Прокси-объект выступает в качестве посредника между клиентом и доступным объектом. Цель прокси-объекта — отслеживать срок жизни доступного объекта и переадресовывать вызовы к объекту со специальными возможностями только в том случае, если он не уничтожен.
Когда клиент вызывает свойство IAccess для получения сведений об объекте, прокси-объект должен проверка, доступен ли доступный объект. Если это так, прокси-объект передает запрос клиента к объекту со специальными возможностями. Если объект со специальными возможностями уничтожается (например, при закрытии диалогового окна с пользовательскими элементами управления), прокси-объект возвращает ошибку. Чтобы указать, что объект был уничтожен, рекомендуется, чтобы серверы возвращали код ошибки CO_E_OBJNOTCONNECTED поскольку эта ошибка возвращается компонентной объектной моделью (COM) после вызова сервером CoDisconnectObject.
Прокси-объект является прозрачным для клиента. Когда клиент вызывает AccessibleObjectFromEvent, AccessibleObjectFromPoint или AccessibleObjectFromWindow, он получает обратный указатель на интерфейс IAccessible . Однако если клиент использует этот указатель для вызова любого из свойств или методов IAccess , выполняемый код находится в прокси-объекте.
Обратная связь
Были ли сведения на этой странице полезными?
Proxy и Reflect
Объект Proxy «оборачивается» вокруг другого объекта и может перехватывать (и, при желании, самостоятельно обрабатывать) разные действия с ним, например чтение/запись свойств и другие. Далее мы будем называть такие объекты «прокси».
Прокси используются во многих библиотеках и некоторых браузерных фреймворках. В этой главе мы увидим много случаев применения прокси в решении реальных задач.
let proxy = new Proxy(target, handler);
- target – это объект, для которого нужно сделать прокси, может быть чем угодно, включая функции.
- handler – конфигурация прокси: объект с «ловушками» («traps»): методами, которые перехватывают разные операции, например, ловушка get – для чтения свойства из target , ловушка set – для записи свойства в target и так далее.
При операциях над proxy , если в handler имеется соответствующая «ловушка», то она срабатывает, и прокси имеет возможность по-своему обработать её, иначе операция будет совершена над оригинальным объектом target .
В качестве начального примера создадим прокси без всяких ловушек:
let target = <>; let proxy = new Proxy(target, <>); // пустой handler proxy.test = 5; // записываем в прокси (1) alert(target.test); // 5, свойство появилось в target! alert(proxy.test); // 5, мы также можем прочитать его из прокси (2) for(let key in proxy) alert(key); // test, итерация работает (3)
Так как нет ловушек, то все операции на proxy применяются к оригинальному объекту target .
- Запись свойства proxy.test= устанавливает значение на target .
- Чтение свойства proxy.test возвращает значение из target .
- Итерация по proxy возвращает значения из target .
Как мы видим, без ловушек proxy является прозрачной обёрткой над target .
Proxy – это особый, «экзотический», объект, у него нет собственных свойств. С пустым handler он просто перенаправляет все операции на target .
Чтобы активировать другие его возможности, добавим ловушки.
Что именно мы можем ими перехватить?
Для большинства действий с объектами в спецификации JavaScript есть так называемый «внутренний метод», который на самом низком уровне описывает, как его выполнять. Например, [[Get]] – внутренний метод для чтения свойства, [[Set]] – для записи свойства, и так далее. Эти методы используются только в спецификации, мы не можем обратиться напрямую к ним по имени.
Ловушки как раз перехватывают вызовы этих внутренних методов. Полный список методов, которые можно перехватывать, перечислен в спецификации Proxy, а также в таблице ниже.
Для каждого внутреннего метода в этой таблице указана ловушка, то есть имя метода, который мы можем добавить в параметр handler при создании new Proxy , чтобы перехватывать данную операцию:
Внутренний метод | Ловушка | Что вызывает |
---|---|---|
[[Get]] | get | чтение свойства |
[[Set]] | set | запись свойства |
[[HasProperty]] | has | оператор in |
[[Delete]] | deleteProperty | оператор delete |
[[Call]] | apply | вызов функции |
[[Construct]] | construct | оператор new |
[[GetPrototypeOf]] | getPrototypeOf | Object.getPrototypeOf |
[[SetPrototypeOf]] | setPrototypeOf | Object.setPrototypeOf |
[[IsExtensible]] | isExtensible | Object.isExtensible |
[[PreventExtensions]] | preventExtensions | Object.preventExtensions |
[[DefineOwnProperty]] | defineProperty | Object.defineProperty, Object.defineProperties |
[[GetOwnProperty]] | getOwnPropertyDescriptor | Object.getOwnPropertyDescriptor, for..in , Object.keys/values/entries |
[[OwnPropertyKeys]] | ownKeys | Object.getOwnPropertyNames, Object.getOwnPropertySymbols, for..in , Object.keys/values/entries |
Инварианты
JavaScript налагает некоторые условия – инварианты на реализацию внутренних методов и ловушек.
Большинство из них касаются возвращаемых значений:
- Метод [[Set]] должен возвращать true , если значение было успешно записано, иначе false .
- Метод [[Delete]] должен возвращать true , если значение было успешно удалено, иначе false .
- …и так далее, мы увидим больше в примерах ниже.
Есть и другие инварианты, например:
- Метод [[GetPrototypeOf]] , применённый к прокси, должен возвращать то же значение, что и метод [[GetPrototypeOf]] , применённый к оригинальному объекту. Другими словами, чтение прототипа объекта прокси всегда должно возвращать прототип оригинального объекта.
Ловушки могут перехватывать вызовы этих методов, но должны выполнять указанные условия.
Инварианты гарантируют корректное и последовательное поведение конструкций и методов языка. Полный список инвариантов можно найти в спецификации, хотя скорее всего вы не нарушите эти условия, если только не соберётесь делать что-то совсем уж странное.
Теперь давайте посмотрим, как это всё работает, на реальных примерах.
Значение по умолчанию с ловушкой «get»
Чаще всего используются ловушки на чтение/запись свойств.
Чтобы перехватить операцию чтения, handler должен иметь метод get(target, property, receiver) .
Он срабатывает при попытке прочитать свойство объекта, с аргументами:
- target – это оригинальный объект, который передавался первым аргументом в конструктор new Proxy ,
- property – имя свойства,
- receiver – если свойство объекта является геттером, то receiver – это объект, который будет использован как this при его вызове. Обычно это сам объект прокси (или наследующий от него объект). Прямо сейчас нам не понадобится этот аргумент, подробнее разберём его позже.
Давайте применим ловушку get , чтобы реализовать «значения по умолчанию» для свойств объекта.
Например, сделаем числовой массив, так чтобы при чтении из него несуществующего элемента возвращался 0 .
Обычно при чтении из массива несуществующего свойства возвращается undefined , но мы обернём обычный массив в прокси, который перехватывает операцию чтения свойства из массива и возвращает 0 , если такого элемента нет:
let numbers = [0, 1, 2]; numbers = new Proxy(numbers, < get(target, prop) < if (prop in target) < return target[prop]; >else < return 0; // значение по умолчанию >> >); alert( numbers[1] ); // 1 alert( numbers[123] ); // 0 (нет такого элемента)
Как видно, это очень легко сделать при помощи ловушки get .
Мы можем использовать Proxy для реализации любой логики возврата значений по умолчанию.
Представим, что у нас есть объект-словарь с фразами на английском и их переводом на испанский:
let dictionary = < 'Hello': 'Hola', 'Bye': 'Adiós' >; alert( dictionary['Hello'] ); // Hola alert( dictionary['Welcome'] ); // undefined
Сейчас, если фразы в dictionary нет, при чтении возвращается undefined . Но на практике оставлять фразы непереведёнными лучше, чем использовать undefined . Поэтому давайте сделаем так, чтобы при отсутствии перевода возвращалась оригинальная фраза на английском вместо undefined .
Чтобы достичь этого, обернём dictionary в прокси, перехватывающий операцию чтения:
let dictionary = < 'Hello': 'Hola', 'Bye': 'Adiós' >; dictionary = new Proxy(dictionary, < get(target, phrase) < // перехватываем чтение свойства в dictionary if (phrase in target) < // если перевод для фразы есть в словаре return target[phrase]; // возвращаем его >else < // иначе возвращаем непереведённую фразу return phrase; >> >); // Запросим перевод произвольного выражения в словаре! // В худшем случае оно не будет переведено alert( dictionary['Hello'] ); // Hola alert( dictionary['Welcome to Proxy']); // Welcome to Proxy (нет перевода)
Прокси следует использовать везде вместо target
Пожалуйста, обратите внимание: прокси перезаписывает переменную:
dictionary = new Proxy(dictionary, . );
Прокси должен заменить собой оригинальный объект повсюду. Никто не должен ссылаться на оригинальный объект после того, как он был проксирован. Иначе очень легко запутаться.
Валидация с ловушкой «set»
Допустим, мы хотим сделать массив исключительно для чисел. Если в него добавляется значение иного типа, то это должно приводить к ошибке.
Ловушка set срабатывает, когда происходит запись свойства.
set(target, property, value, receiver) :
- target – это оригинальный объект, который передавался первым аргументом в конструктор new Proxy ,
- property – имя свойства,
- value – значение свойства,
- receiver – аналогично ловушке get , этот аргумент имеет значение, только если свойство – сеттер.
Ловушка set должна вернуть true , если запись прошла успешно, и false в противном случае (будет сгенерирована ошибка TypeError ).
Давайте применим её для проверки новых значений:
let numbers = []; numbers = new Proxy(numbers, < // (*) set(target, prop, val) < // для перехвата записи свойства if (typeof val == 'number') < target[prop] = val; return true; >else < return false; >> >); numbers.push(1); // добавилось успешно numbers.push(2); // добавилось успешно alert("Длина: " + numbers.length); // 2 numbers.push("тест"); // TypeError (ловушка set на прокси вернула false) alert("Интерпретатор никогда не доходит до этой строки (из-за ошибки в строке выше)");
Обратите внимание, что встроенная функциональность массива по-прежнему работает! Значения добавляются методом push . Свойство length при этом увеличивается. Наш прокси ничего не ломает.
Нам не нужно переопределять методы массива push и unshift и другие, чтобы добавлять туда проверку на тип, так как внутри себя они используют операцию [[Set]] , которая перехватывается прокси.
Таким образом, код остаётся чистым и прозрачным.
Не забывайте вернуть true
Как сказано ранее, нужно соблюдать инварианты.
Для set реализация ловушки должна возвращать true в случае успешной записи свойства.
Если забыть это сделать или возвратить любое ложное значение, это приведёт к ошибке TypeError .
Перебор при помощи «ownKeys» и «getOwnPropertyDescriptor»
Object.keys , цикл for..in и большинство других методов, которые работают со списком свойств объекта, используют внутренний метод [[OwnPropertyKeys]] (перехватываемый ловушкой ownKeys ) для их получения.
Такие методы различаются в деталях:
- Object.getOwnPropertyNames(obj) возвращает не-символьные ключи.
- Object.getOwnPropertySymbols(obj) возвращает символьные ключи.
- Object.keys/values() возвращает не-символьные ключи/значения с флагом enumerable (подробнее про флаги свойств было в главе Флаги и дескрипторы свойств).
- for..in перебирает не-символьные ключи с флагом enumerable , а также ключи прототипов.
…Но все они начинают с этого списка.
В примере ниже мы используем ловушку ownKeys , чтобы цикл for..in по объекту, равно как Object.keys и Object.values пропускали свойства, начинающиеся с подчёркивания _ :
let user = < name: "Вася", age: 30, _password: "***" >; user = new Proxy(user, < ownKeys(target) < return Object.keys(target).filter(key =>!key.startsWith('_')); > >); // ownKeys исключил _password for(let key in user) alert(key); // name, затем: age // аналогичный эффект для этих методов: alert( Object.keys(user) ); // name,age alert( Object.values(user) ); // Вася,30
Как видно, работает.
Впрочем, если мы попробуем возвратить ключ, которого в объекте на самом деле нет, то Object.keys его не выдаст:
let user = < >; user = new Proxy(user, < ownKeys(target) < return ['a', 'b', 'c']; >>); alert( Object.keys(user) ); //
Почему? Причина проста: Object.keys возвращает только свойства с флагом enumerable . Для того, чтобы определить, есть ли этот флаг, он для каждого свойства вызывает внутренний метод [[GetOwnProperty]] , который получает его дескриптор. А в данном случае свойство отсутствует, его дескриптор пуст, флага enumerable нет, поэтому оно пропускается.
Чтобы Object.keys возвращал свойство, нужно либо чтобы свойство в объекте физически было, причём с флагом enumerable , либо перехватить вызовы [[GetOwnProperty]] (это делает ловушка getOwnPropertyDescriptor ), и там вернуть дескриптор с enumerable: true .
Вот так будет работать:
let user = < >; user = new Proxy(user, < ownKeys(target) < // вызывается 1 раз для получения списка свойств return ['a', 'b', 'c']; >, getOwnPropertyDescriptor(target, prop) < // вызывается для каждого свойства return < enumerable: true, configurable: true /* . другие флаги, возможно, "value: . " */ >; > >); alert( Object.keys(user) ); // a, b, c
Ещё раз заметим, что получение дескриптора нужно перехватывать только если свойство отсутствует в самом объекте.
Защищённые свойства с ловушкой «deleteProperty» и другими
Существует широко распространённое соглашение о том, что свойства и методы, название которых начинается с символа подчёркивания _ , следует считать внутренними. К ним не следует обращаться снаружи объекта.
Однако технически это всё равно возможно:
let user = < name: "Вася", _password: "secret" >; alert(user._password); // secret
Давайте применим прокси, чтобы защитить свойства, начинающиеся на _ , от доступа извне.
Нам будут нужны следующие ловушки:
- get – для того, чтобы сгенерировать ошибку при чтении такого свойства,
- set – для того, чтобы сгенерировать ошибку при записи,
- deleteProperty – для того, чтобы сгенерировать ошибку при удалении,
- ownKeys – для того, чтобы исключить такие свойства из for..in и методов типа Object.keys .
Вот соответствующий код:
let user = < name: "Вася", _password: "***" >; user = new Proxy(user, < get(target, prop) < if (prop.startsWith('_')) < throw new Error("Отказано в доступе"); >else < let value = target[prop]; return (typeof value === 'function') ? value.bind(target) : value; // (*) >>, set(target, prop, val) < // перехватываем запись свойства if (prop.startsWith('_')) < throw new Error("Отказано в доступе"); >else < target[prop] = val; return true; >>, deleteProperty(target, prop) < // перехватываем удаление свойства if (prop.startsWith('_')) < throw new Error("Отказано в доступе"); >else < delete target[prop]; return true; >>, ownKeys(target) < // перехватываем попытку итерации return Object.keys(target).filter(key =>!key.startsWith('_')); > >); // "get" не позволяет прочитать _password try < alert(user._password); // Error: Отказано в доступе >catch(e) < alert(e.message); >// "set" не позволяет записать _password try < user._password = "test"; // Error: Отказано в доступе >catch(e) < alert(e.message); >// "deleteProperty" не позволяет удалить _password try < delete user._password; // Error: Отказано в доступе >catch(e) < alert(e.message); >// "ownKeys" исключает _password из списка видимых для итерации свойств for(let key in user) alert(key); // name
Обратите внимание на важную деталь в ловушке get на строке (*) :
get(target, prop) < // . let value = target[prop]; return (typeof value === 'function') ? value.bind(target) : value; // (*) >
Зачем для функции вызывать value.bind(target) ?
Всё дело в том, что метод самого объекта, например user.checkPassword() , должен иметь доступ к свойству _password :
user = < // . checkPassword(value) < // метод объекта должен иметь доступ на чтение _password return value === this._password; >>
Вызов user.checkPassword() получает проксированный объект user в качестве this (объект перед точкой становится this ), так что когда такой вызов обращается к this._password , ловушка get вступает в действие (она срабатывает при любом чтении свойства), и выбрасывается ошибка.
Поэтому мы привязываем контекст к методам объекта – оригинальный объект target в строке (*) . Тогда их дальнейшие вызовы будут использовать target в качестве this , без всяких ловушек.
Такое решение обычно работает, но не является идеальным, поскольку метод может передать оригинальный объект куда-то ещё, и возможна путаница: где изначальный объект, а где – проксированный.
К тому же, объект может проксироваться несколько раз (для добавления различных возможностей), и если передавать методу исходный, то могут быть неожиданности.
Так что везде использовать такой прокси не стоит.
Приватные свойства в классах
Современные интерпретаторы JavaScript поддерживают приватные свойства в классах. Названия таких свойств должны начинаться с символа # . Они подробно описаны в главе Приватные и защищённые методы и свойства. Для них не нужны подобные прокси.
Впрочем, приватные свойства имеют свои недостатки. В частности, они не наследуются.
«В диапазоне» с ловушкой «has»
Давайте посмотрим ещё примеры.
Предположим, у нас есть объект range , описывающий диапазон:
let range = < start: 1, end: 10 >;
Мы бы хотели использовать оператор in , чтобы проверить, что некоторое число находится в указанном диапазоне.
Ловушка has перехватывает вызовы in .
- target – это оригинальный объект, который передавался первым аргументом в конструктор new Proxy ,
- property – имя свойства
let range = < start: 1, end: 10 >; range = new Proxy(range, < has(target, prop) < return prop >= target.start && prop >); alert(5 in range); // true alert(50 in range); // false
Отлично выглядит, не правда ли? И очень просто в реализации.
Оборачиваем функции: «apply»
Мы можем оборачивать в прокси и функции.
Ловушка apply(target, thisArg, args) активируется при вызове прокси как функции:
- target – это оригинальный объект (как мы помним, функция – это объект в языке JavaScript),
- thisArg – это контекст this .
- args – список аргументов.
Например, давайте вспомним декоратор delay(f, ms) , созданный нами в главе Декораторы и переадресация вызова, call/apply.
Тогда мы обошлись без создания прокси. Вызов delay(f, ms) возвращал функцию, которая передавала вызовы f после ms миллисекунд.
Вот предыдущая реализация, на основе функции:
function delay(f, ms) < // возвращает обёртку, которая вызывает функцию f через таймаут return function() < // (*) setTimeout(() =>f.apply(this, arguments), ms); >; > function sayHi(user) < alert(`Привет, $!`); > // после обёртки вызовы sayHi будут срабатывать с задержкой в 3 секунды sayHi = delay(sayHi, 3000); sayHi("Вася"); // Привет, Вася! (через 3 секунды)
Как мы уже видели, это в целом работает. Функция-обёртка в строке (*) вызывает нужную функцию с указанной задержкой.
Но наша функция-обёртка не перенаправляет операции чтения/записи свойства и другие. После обёртывания доступ к свойствам оригинальной функции, таким как name , length , и другим, будет потерян.
function delay(f, ms) < return function() < setTimeout(() =>f.apply(this, arguments), ms); >; > function sayHi(user) < alert(`Привет, $!`); > alert(sayHi.length); // 1 (в функции length - это число аргументов в её объявлении) sayHi = delay(sayHi, 3000); alert(sayHi.length); // 0 (в объявлении функции-обёртки ноль аргументов)
Прокси куда более мощные в этом смысле, поскольку они перенаправляют всё к оригинальному объекту.
Давайте используем прокси вместо функции-обёртки:
function delay(f, ms) < return new Proxy(f, < apply(target, thisArg, args) < setTimeout(() =>target.apply(thisArg, args), ms); > >); > function sayHi(user) < alert(`Привет, $!`); > sayHi = delay(sayHi, 3000); alert(sayHi.length); // 1 (*) прокси перенаправляет чтение свойства length на исходную функцию sayHi("Вася"); // Привет, Вася! (через 3 секунды)
Результат такой же, но сейчас не только вызовы, но и другие операции на прокси перенаправляются к оригинальной функции. Таким образом, операция чтения свойства sayHi.length возвращает корректное значение в строке (*) после проксирования.
Мы получили лучшую обёртку.
Существуют и другие ловушки: полный список есть в начале этой главы. Использовать их можно по аналогии с вышеописанными.
Reflect
Reflect – встроенный объект, упрощающий создание прокси.
Ранее мы говорили о том, что внутренние методы, такие как [[Get]] , [[Set]] и другие, существуют только в спецификации, что к ним нельзя обратиться напрямую.
Объект Reflect делает это возможным. Его методы – минимальные обёртки вокруг внутренних методов.
Вот примеры операций и вызовы Reflect , которые делают то же самое:
Операция | Вызов Reflect | Внутренний метод |
---|---|---|
obj[prop] | Reflect.get(obj, prop) | [[Get]] |
obj[prop] = value | Reflect.set(obj, prop, value) | [[Set]] |
delete obj[prop] | Reflect.deleteProperty(obj, prop) | [[Delete]] |
new F(value) | Reflect.construct(F, value) | [[Construct]] |
… | … | … |