Jakiś czas temu widziałem pusty fragment na MDN dla Reflect
obiektu w javascript, ale za całe życie nie mogę znaleźć niczego w Google. Dzisiaj znalazłem ten http://people.mozilla.org/~jorendorff/es6-draft.html#sec-reflect-object i brzmi podobnie do obiektu Proxy, poza dziedziną i funkcjonalnością programu ładującego.
Zasadniczo nie wiem, czy ta strona, którą znalazłem, wyjaśnia tylko, jak zaimplementować Reflect, czy po prostu nie rozumiem jej sformułowania. Czy mógłby mi ktoś ogólnie wyjaśnić jakie metodyReflect
to zrobić?
Na przykład na stronie, którą znalazłem, jest napisane, że wywołanie Reflect.apply ( target, thisArgument, argumentsList )
zwróci wynik wywołania wewnętrznej metody [[Call]] celu z argumentami thisArgument i args. ale czym to się różni od zwykłego dzwonienia target.apply(thisArgument, argumentsList)
?
Aktualizacja:
Dzięki @Blue znalazłem tę stronę na wiki http://wiki.ecmascript.org/doku.php?id=harmony:reflect_api&s=reflect,
która według mojej najlepszej wiedzy mówi, że obiekt Reflect
dostarcza wersje metod wszystkich działania, które mogą zostać przechwycone przez serwery proxy, aby ułatwić przekazywanie. Ale wydaje mi się to trochę dziwne, ponieważ nie rozumiem, jak to jest całkowicie konieczne. Ale wydaje się, że robi trochę więcej niż to, szczególnie par, który mówi, double-lifting
ale wskazuje na starą specyfikację proxy /
źródło
Reflect
jest to tylko pojemnik naRealm
iLoader
obiekty, ale nie wiem, co robią te ostatnie.Reflect.Loader
iReflect.Realm
mieć coś wspólnego z przeciążaniem funkcjonalności modułu?isExtensible
,ownKeys
itd. W ES 6, z rzeczywistych klas, to jest użyteczne, aby dowiedzieć się więcej o klasie (target
w 16.1.2 myślę).Odpowiedzi:
UPDATE 2015: Jak podkreślił 7 „s odpowiedź , teraz ES6 (ECMAScript 2015) została sfinalizowana, bardziej odpowiednia dokumentacja jest już dostępny:
Oryginalna odpowiedź (dla (historycznego) zrozumienia i dodatkowych przykładów) :
Reflection proposal
Wydaje się, że postęp w projekcie specyfikacji ECMAScript 6 . Ten dokument obecnie przedstawia wReflect
zarysie metody -obiektu i podaje tylko następujące informacjeReflect
dotyczące samego -obiektu:Jednak istnieje krótkie wyjaśnienie jego celu w ES Harmony :
Tak więc
Reflect
obiekt zapewnia szereg funkcji narzędziowych, z których wiele wydaje się pokrywać z metodami ES5 zdefiniowanymi w globalnym Object.Jednak to nie wyjaśnia, jakie istniejące problemy ma to rozwiązać, ani jakie funkcje zostały dodane. Podejrzewałem, że można to zniwelować i rzeczywiście, powyższa specyfikacja harmonii łączy się z „nienormatywną, przybliżoną implementacją tych metod” .
Zbadanie tego kodu może dać (dalsze) wyobrażenie o jego użyciu, ale na szczęście istnieje również wiki, które przedstawia szereg powodów, dla których obiekt Reflect jest przydatny :
(Skopiowałem (i sformatowałem) następujący tekst do wykorzystania w przyszłości z tego bo to jedyne przykłady, jakie udało mi się znaleźć. Poza tym mają sens, mają już dobre wyjaśnienie i dotykają
apply
przykładu pytania ).Bardziej przydatne wartości zwracane
Wiele operacji w programie
Reflect
jest podobnych do operacji ES5 zdefiniowanych wObject
, takich jakReflect.getOwnPropertyDescriptor
iReflect.defineProperty
. Jednak podczas gdy funkcjaObject.defineProperty(obj, name, desc)
zwróci,obj
gdy właściwość została pomyślnie zdefiniowana, lub wyrzuci wTypeError
przeciwnym razie, określonoReflect.defineProperty(obj, name, desc)
po prostu zwrócenie wartości logicznej, która wskazuje, czy właściwość została pomyślnie zdefiniowana. Pozwala to na refaktoryzację tego kodu:try { Object.defineProperty(obj, name, desc); // property defined successfully } catch (e) { // possible failure (and might accidentally catch the wrong exception) }
Do tego:
if (Reflect.defineProperty(obj, name, desc)) { // success } else { // failure }
Inne metody, które zwracają taki logiczny status sukcesu, to
Reflect.set
(aby zaktualizować właściwość),Reflect.deleteProperty
(aby usunąć właściwość),Reflect.preventExtensions
(aby obiekt nie był rozszerzalny) iReflect.setPrototypeOf
(aby zaktualizować łącze prototypu obiektu).Operacje pierwszej klasy
W ES5 sposobem na wykrycie, czy obiekt
obj
definiuje lub dziedziczy określoną nazwę właściwości, jest zapis(name in obj)
. Podobnie, aby usunąć właściwość, używa siędelete obj[name]
. Chociaż dedykowana składnia jest ładna i krótka, oznacza to również, że musisz jawnie opakować te operacje w funkcje, jeśli chcesz przekazać operację jako wartość pierwszej klasy.Dzięki temu
Reflect
operacje te można łatwo zdefiniować jako funkcje pierwszej klasy:Reflect.has(obj, name)
jest funkcjonalnym odpowiednikiem(name in obj)
iReflect.deleteProperty(obj, name)
jest funkcją, która robi to samo, codelete obj[name].
Bardziej niezawodna aplikacja funkcji
W ES5, gdy chce się wywołać funkcję
f
ze zmienną liczbą argumentów spakowanych jako tablicaargs
i wiążącąthis
wartość doobj
, można napisać:Jednak
f
może to być obiekt, który celowo lub nieumyślnie definiuje własnąapply
metodę. Jeśli naprawdę chcesz się upewnić, żeapply
wywoływana jest funkcja wbudowana , zazwyczaj pisze się:Function.prototype.apply.call(f, obj, args)
Jest to nie tylko gadatliwe, ale szybko staje się trudne do zrozumienia. Dzięki
Reflect
, możesz teraz wykonać niezawodne wywołanie funkcji w krótszy i łatwiejszy do zrozumienia sposób:Reflect.apply(f, obj, args)
Konstruktory ze zmiennymi argumentami
Wyobraź sobie, że chcesz wywołać funkcję konstruktora ze zmienną liczbą argumentów. W ES6, dzięki nowej składni spreadów, będzie można pisać kod taki jak:
var obj = new F(...args)
W ES5 jest to trudniejsze do napisania, ponieważ można używać
F.apply
lubF.call
wywoływać tylko funkcję ze zmienną liczbą argumentów, ale nie maF.construct
funkcji donew
funkcji ze zmienną liczbą argumentów. DziękiReflect
, można teraz pisać, w ES5:var obj = Reflect.construct(F, args)
Domyślne zachowanie przekazywania dla pułapek proxy
Podczas używania
Proxy
obiektów do zawijania istniejących obiektów, bardzo często przechwytuje się operację, robi coś, a następnie „robi coś domyślnego”, co zazwyczaj polega na zastosowaniu przechwyconej operacji na opakowanym obiekcie. Na przykład, powiedzmy, że chcę po prostu rejestrować dostęp do wszystkich właściwości obiektuobj
:var loggedObj = new Proxy(obj, { get: function(target, name) { console.log("get", target, name); // now do the default thing } });
Funkcje API
Reflect
i zostały zaprojektowane w tandemie , tak że dla każdej pułapki istnieje odpowiednia metoda, która „robi coś domyślnego”. Dlatego za każdym razem, gdy chcesz wykonać „domyślną” czynność wewnątrz procedury obsługi proxy, należy zawsze wywołać odpowiednią metodę w obiekcie:Proxy
Proxy
Reflect
Reflect
var loggedObj = new Proxy(obj, { get: function(target, name) { console.log("get", target, name); return Reflect.get(target, name); } });
Zwracany typ
Reflect
metod jest zgodny z typem zwracanymProxy
pułapek.Kontroluj to powiązanie akcesorów
W ES5 dość łatwo jest wykonać ogólny dostęp do właściwości lub aktualizację właściwości. Na przykład:
var name = ... // get property name as a string obj[name] // generic property lookup obj[name] = value // generic property update
Te
Reflect.get
iReflect.set
metody pozwalają zrobić to samo, ale dodatkowo przyjąć jako ostatnia opcjonalnym argumentem jestreceiver
parametr, który pozwala jawnie ustawićthis
-binding gdy właściwość, że masz / zestaw jest accessor:var name = ... // get property name as a string Reflect.get(obj, name, wrapper) // if obj[name] is an accessor, it gets run with `this === wrapper` Reflect.set(obj, name, value, wrapper)
Jest to czasami przydatne, gdy pakujesz
obj
i chcesz, aby wszelkie wysyłki własne w akcesorium zostały przekierowane do twojego opakowania, np. Jeśliobj
jest zdefiniowane jako:var obj = { get foo() { return this.bar(); }, bar: function() { ... } }
Wywołanie
Reflect.get(obj, "foo", wrapper)
spowodujethis.bar()
przekierowanie połączenia dowrapper
.Unikaj dziedzictwa
__proto__
W niektórych przeglądarkach
__proto__
jest definiowana jako specjalna właściwość, która zapewnia dostęp do prototypu obiektu. ES5 ustandaryzowała nową metodęObject.getPrototypeOf(obj)
odpytywania prototypu.Reflect.getPrototypeOf(obj)
robi dokładnie to samo, z tą różnicą, żeReflect
definiuje również odpowiedniReflect.setPrototypeOf(obj, newProto)
do ustawienia prototyp obiektu. Jest to nowy sposób aktualizowania prototypu obiektu, zgodny z ES6.Należy pamiętać, że:
setPrototypeOf
również istnieje naObject
(jak słusznie wskazał KNU „s komentarzu )!EDYCJA:
Uwaga dodatkowa (adresowanie komentarzy do pytającego): Istnieje krótka i prosta odpowiedź na temat „P: Moduły ES6 a import HTML”, która wyjaśnia
Realms
i przedstawiaLoader
obiekty.Inne wyjaśnienie można znaleźć pod tym linkiem :
Warto jednak wspomnieć:
wszystko to jest wciąż w wersji roboczej, to nie jest specyfikacja wyryta w kamieniu!To ES6, więc pamiętaj o zgodności z przeglądarkami!Mam nadzieję że to pomoże!
źródło
Reflect.apply
itarget.apply
? Albo co powinienem dodać przed zakończeniem nagrody?Object
.Reflect.get
jako domyślnej implementacji dla proxy get nie działa dobrze, jeśli pośredniczysz w obiekcie z właściwościami prototypu. Po prostu narzeka, że nie działa. Jednak jeśli zamiast tego użyjeszReflect.get(target, property)
bez przekazywaniareceiver
, to zadziała.target
jest pierwotnym celem opakowanym przez proxy, podczas gdyreceiver
jest to samo proxy. Ale znowu może to wyglądać inaczej, jeśli uzyskasz dostęp do właściwości w inny sposób.Przechodząc przez projekt dokumentu znalezionego na wiki,
http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts
Otrzymujemy wiersz o „pojedynczym zwykłym przedmiocie”, który wyjaśnia w szkicu. Zawiera również definicje funkcji.
Witryna wiki powinna być wiarygodna, ponieważ link do niej można znaleźć na stronie internetowej emcascript
http://www.ecmascript.org/dev.php
Znalazłem jednak pierwszy link przez Google i nie miałem szczęścia, aby go znaleźć, przeszukując bezpośrednio wiki.
źródło