JS __proto__ „zabawny” fakt

Nov 26 2022
Jeśli śledzisz mnie wystarczająco długo, wiesz już, jak bardzo zawsze byłem przeciwny __proto__, a jednak, odkąd dawno temu dotarł do standardu ECMAScript, wciąż są rzadkie okazje, w których znajduję przynajmniej jego użycie do znakowania obiektu akceptowalne: Odkładając na bok wydajność i proszę zauważyć, że w ogóle nie sugeruję użycia __proto__ na wolności, ten post istnieje z innych powodów. Obiekt.
Zdjęcie Marka Williamsa na Unsplash

Jeśli śledzisz mnie wystarczająco długo, już wiesz, jak bardzo __proto__zawsze byłem przeciwny, a jednak, odkąd dawno temu dotarł do standardu ECMAScript , wciąż zdarzają się rzadkie sytuacje, w których uważam, że przynajmniej jego użycie do oznakowania obiektu jest akceptowalne :

const factory = (fields, {prototype} = Object) => ({
  __proto__: prototype,
  ...fields
});

// mimic an <a /> reference
factory({href: '/'}, HTMLAnchorElement);

W Firefoksie __proto__ uzyskuje lepsze wyniki niż new Class

Odkładając wydajność na bok i pamiętaj, że nie sugeruję używania __proto__w ogóle na wolności, ten post istnieje z innych powodów.

Obiekt.prototyp.__proto__

Jestem prawie pewien, że każdy wie, co robi akcesor __proto__ , więc chciałbym zaproponować ci wyzwanie… i tak, to wszystko jest poprawnym JS:

class Test {}
const __proto__ = Test.prototype;

// what do these operations return?
({__proto__} instanceof Test);
({__proto__: __proto__} instanceof Test);
({"__proto__": __proto__} instanceof Test);
({["__proto__"]: __proto__} instanceof Test);

// what do these operations return?
({__proto__}.__proto__ === Test.prototype);
({__proto__: __proto__}.__proto__ === Test.prototype);
({"__proto__": __proto__}.__proto__ === Test.prototype);
({["__proto__"]: __proto__}.__proto__ === Test.prototype);

Jeśli nie uruchomiłeś tych fragmentów, aby poznać odpowiedź, mogę w tym pomóc! W pierwszym wyzwaniu wynikiem będzie false, true, truei falseznowu, a powodem jest to, że oba {__proto__}i {["__proto__"]}zdefiniowane jako własna właściwość , podczas gdy przypisanie za pomocą składni, bez użycia specjalnych funkcji składni, nawet z cudzysłowami, przechodzi faktycznie przez Object.prototype.__proto__akcesor.

Z drugiej strony, w drugim wyzwaniu (all true) tak naprawdę nie ma znaczenia, czy uzyskujemy dostęp __proto__bezpośrednio, czy jako ["__proto__"], więc w zasadzie nie ma symetrii w sposobie, w jaki możemy uruchomić __proto__setera, od sposobu, w jaki możemy uruchomić __proto__gettera raz albo jest to własność własna, albo magiczna brama spadkowa.

…i nie tylko __proto__

Nie sprawdzałem tego osobiście, ale uważam, że każdy starszy __xxx__specjalny akcesor cierpi na tę samą __proto__klątwę, więc bądź ostrożny, mieszając najnowszą fajną składnię JS, aby przypisać właściwości z twoimi faktycznymi intencjami i oczekiwaniami, ponieważ wszystko może łatwo pójść na marne, jeśli spróbujesz bądź sprytny w przypisywaniu tych właściwości .

I to wszystko ludzie!

Jedyny wniosek z tego postu jest prawdopodobnie podsumowany w następujący sposób:

  • nie używaj starszych, ale działających części języka, jeśli chcesz uniknąć niespodzianek dzisiaj lub jutro, jak zachowują się one z nową składnią
  • preferuj jawne (i niestety wolniejsze) Object.setPrototypeOfzawsze, gdy ręczne ustawienie prototypu obiektu jest bezwzględnie wymagane, ale używaj klas w każdym innym przypadku, kiedy tylko jest to możliwe
  • wymaż ten post z pamięci lub skróć go do krótkiego zdania, takiego jak: „ Nigdy nie powinienem używać __proto__w moim kodzie ” i idź dalej, ucząc się wymyślnych nowych rzeczy, które nie zaśmiecają twojego mózgu ani uczuć