Dlaczego rozszerzenie prototypów DOM / wbudowanych obiektów jest złym pomysłem?

15

Szukam ostatecznej odpowiedzi na pytanie, dlaczego rozszerzanie wbudowanych prototypów jest tak surowo karane w społeczności programistów JS. Od jakiegoś czasu korzystam z frameworka JS Prototype i [1,2,3].each(doStuff)wydaje mi się, że jest o wiele bardziej elegancki niż $.each([1,2,3], doStuff). Wiem, że powoduje to „zanieczyszczenie przestrzeni nazw”, ale nie rozumiem, dlaczego uważa się to za coś złego. Czy istnieje też jakikolwiek rzeczywisty spadek wydajności związany z rozszerzaniem wbudowanych prototypów? Dzięki!

lxe
źródło
1
Jedną rzeczą jest to, że for(var ... in ...)pętle są pomieszane, ponieważ przekazywane są również funkcje prototypowe.
pimvdb
4
„mocno karane”, naprawdę ?! dobry Boże, człowieku:] wszystko w porządku?
pixelbobby

Odpowiedzi:

12

Proponuję ci przeczytać tego artykułu, który moim zdaniem wyjaśnia całkiem dobrze, dlaczego rozszerzanie obiektów jest złym pomysłem, również w odniesieniu do Prototypu.

W podsumowaniu:

Brak specyfikacji

Ujawnienie „obiektów prototypowych” nie jest częścią żadnej specyfikacji. [...] Aby implementacja była w pełni zgodna z DOM Level 2, nie trzeba ujawniać tych globalnych obiektów Node, Element, HTMLElement itp.

Obiekty hosta nie mają reguł

Obiekty DOM są obiektami hosta [...] Obiekty hosta mogą implementować te metody wewnętrzne z zachowaniem zależnym od implementacji lub może być tak, że obiekt hosta implementuje tylko niektóre metody wewnętrzne, a nie inne.

[...] Zachowanie metod wewnętrznych zależy od implementacji. [...] Z definicji pracujesz z czymś, co może zachowywać się w nieprzewidywalny i całkowicie nieobliczalny sposób.

Szansa na kolizje

Biorąc pod uwagę ogromną liczbę używanych obecnie środowisk, nie można stwierdzić, czy określona właściwość nie jest już częścią jakiegoś DOM. [...]

Każda nazwana właściwość cienia kontroluje właściwości dziedziczone przez łańcuch prototypów. Prawdopodobieństwo kolizji i nieoczekiwanych błędów elementów formularza jest jeszcze większe.

Zastosowanie pewnego rodzaju strategii prefiksowania może złagodzić problem. Ale prawdopodobnie przyniesie również dodatkowy hałas.

Koszty ogólne wydajności

[...] przeglądarki, które nie obsługują rozszerzeń elementów - takie jak IE 6, 7, Safari 2.x itp. - wymagają ręcznego rozszerzenia obiektów. Problem polega na tym, że ręczne przedłużanie jest powolne, niewygodne i nie skaluje się.

[...] po rozpoczęciu rozszerzania elementów interfejs API biblioteki najprawdopodobniej musi zwrócić elementy rozszerzone wszędzie. W rezultacie metody zapytań, takie jak $$, mogą w końcu rozszerzyć każdy element w zapytaniu.

IE DOM to bałagan

Jak pokazano w poprzedniej sekcji, ręczne rozszerzenie DOM jest bałaganem. Ale ręczne rozszerzenie DOM w IE jest jeszcze gorsze [...]

Bonus: błędy przeglądarki

Jose Faeti
źródło
9

Innym powodem jest czytelność / konserwacja kodu. Jeśli inny programista (szczególnie początkujący) czyta mój kod i widzi[0, 1, 2].foo(...) , może nie wiedzieć, co to jest metoda foo lub gdzie znaleźć dokumentację / źródło dla niej. Czy foo jest rozszerzeniem języka dodanego przez prototype.js, inną używaną bibliotekę lub inną część mojego kodu w innym pliku, czy jest to natywna metoda JavaScript, o której nie wiedzieli? Muszą na nie polować i mogą go nie znaleźć od razu (lub jeśli występują konflikty, mogą nie znaleźć właściwego).

Jeśli widzisz podejście jQuery, $.foo(...)przestrzeń nazw metody foo wyraźnie pokazuje, gdzie można znaleźć jej definicję / dokumentację, jeśli nie wiesz, co ona robi.

Bruce Harris
źródło
Odkrycie, skąd pochodzą metody, jest bardzo ważne dla czytelników. Chociaż tak naprawdę nie uważam, że jQuery jest dobrym przykładem, ponieważ znak dolara jest trudny w wyszukiwaniu, kiedy zaczynasz czytać kod sieciowy i nie wiesz już, co to jest.
Simon Feltman
4

Oto podstawowy problem: co się stanie, jeśli masz dwa narzędzia, które rozszerzają prototypy w niekompatybilny sposób, lub które rozszerzają powszechnie nazywane metody w taki sposób, że dają różne wyniki (jest to szczególny problem for...inw JavaScript), powodując w ten sposób kod zależny na ich normalnym zachowaniu do zerwania?

Zasadniczo są to te same problemy, które występują przy niewłaściwym użyciu zmiennych globalnych. Samo w sobie może nie dzieje się nic złego. Ale to otwiera cię na kłopoty, gdy nagle dwa pozornie oddzielne fragmenty kodu natrafiają na siebie (a debugowanie, kiedy to się dzieje, jest trudne).

Z pewnością prototype.js jest dość dobrze znany i większość narzędzi działa w oparciu o to, co robi. Podobnie, jestem pewien, że istnieją przypadki, w których rozszerzenie prototypów podstawowych jest właściwym rozwiązaniem. Ale do tego należy podchodzić ostrożnie.


źródło
1

Nie jestem pewien, czy to nadal jest problem, ale moje doświadczenia z wcześniejszymi wersjami programu Internet Explorer są takie, że czasami nie było nawet możliwe rozszerzenie niektórych wbudowanych typów.


źródło
1

Istnieją tutaj dwa osobne problemy. Pierwszym z nich jest ogólne rozszerzenie wbudowanych prototypów, a drugim - rozszerzenie prototypów DOM. Argumenty przeciwko rozszerzaniu wbudowanych prototypów:

  • Potencjalne starcia: dwa fragmenty kodu z różnych źródeł, oba definiujące tę samą właściwość na tym samym prototypie
  • Efekty uboczne: rozszerzenie Array.prototypelub Object.prototypemoże mieć efekt domina, taki jak dodanie metod rozszerzenia wyliczanych w for...inpętli

Jeśli chodzi o rozszerzanie prototypów DOM, powyższy argument potencjalnego zderzenia nadal obowiązuje. Ponadto węzły DOM są obiektami hosta i jako takie nie podlegają żadnej z normalnych zasad rodzimych obiektów JavaScript. Mogą zasadniczo robić to, co lubią i nie są zobowiązani do dostarczania sensownych obiektów prototypowych, a nawet dopuszczania dodatkowych właściwości („expando”). IE w szczególności skorzysta z tego prawa, zapewniając żadnych prototypów DOM dla obiektów przed IE 9 i posiadające różne weirdnesses o właściwościach na różnych obiektach DOM (chociaż jesteś ogólnie OK właściwości przypisanie elementów, przewidzianych zestaw Nic document.expandosię false).

Tim Down
źródło