Zauważ, że wszystkie moje argumenty opieram na rzeczywistych przypadkach użycia. Kontrargumenty, których nie można kopii zapasowej przykładem użycia w prawdziwych, kompletnych, interesujących i użytecznych aplikacjach, są nieprawidłowe. Widziałem małe „demonstracje językowe”, które mają wszyscy inni, widziałem posty na blogu opisujące, w jaki sposób prototypy i dynamiczne pisanie tworzą trywialny mały przykład o kilka wierszy krótszy niż w języku C #, ale te po prostu nie są istotne na problemy, na które napotykasz pisanie prawdziwego
kodu zamiast mikro-demonstracji i zabawek. Oto moje problemy z JS:
a) Magiczne „to”. To jest to, z wyjątkiem kiedy to jest to. JavaScript popycha cię do korzystania z anonimowych funkcji w dowolnym miejscu, z wyjątkiem tego, że zawsze tracą odpowiedni kontekst dla zmiennej „this”, więc w końcu masz głupi kod, taki jak „var _this = this”, i używasz tego w twoich callbackach lub innych funkcjach. W niektóre dni przysięgam, że liczba funkcji, które udaje mi się napisać i które nie używają przemianowanych „to”, są w rzeczywistości mniejsze niż liczba, która to robi.
b) 1 + „1” - 1 = 10. Również „1” + 0 = „10”. Tak, to faktycznie spowodowało błędy w naszych aplikacjach, w których dane, które powinny być liczbą, zostały załadowane z pliku JSON jako ciąg znaków z powodu błędu w innej aplikacji, a wynik nie był dobry. Cały nasz kod ładujący musiał zostać zaktualizowany, aby dodać mnóstwo konwersji typu w całym miejscu. Kiedy potrzebuję czegoś, aby być liczbą, naprawdę cholernie chcę, żeby to była liczba, a nie ciąg znaków, obiekt, zero lub cokolwiek innego. Lua, która pod wieloma względami jest bardzo podobna do JavaScript, naprawiła ten problem, po prostu nie będąc wystarczająco opóźnionym, aby użyć tego samego operatora do dodawania i łączenia łańcuchów.
c) Zmienne globalne domyślnie. Nawet jeśli weźmiesz argument, że dynamiczne pisanie jest po prostu „łatwiejsze”, ponieważ nie musisz myśleć o deklaracjach zmiennych, JavaScript wyrzuca ten argument przez okno, umieszczając „var” przed nowymi identyfikatorami w dowolnym miejscu . A potem cicho cię wkręca, jeśli zapomnisz.
d) Prototypy zamiast klas. Istnieje bardzo niewiele rzeczywistych aplikacji JavaScript na dużą skalę, które nie podłączają własnego systemu klas, aby obejść wrodzoną bezużyteczność prototypów w architekturze dużych aplikacji. Te same aplikacje w minimalnym stopniu wykorzystują prototypy w celu rozszerzenia podstawowych typów JavaScript i tylko dlatego, że JS był tak źle zaprojektowany, że nawet dwa ciekawe wbudowane typy, których on oferuje, nie mają połowy cech, których można by się spodziewać.
e) Niemożność tworzenia typów wartości dodanej. W rzeczywistości jest to częsty problem w prawie każdym języku oprócz C ++ / D. Dla tych, którzy używają JavaScript do pisania aplikacji WebGL, spójrz na wszystkie biblioteki algebry liniowej dla JavaScript. W aplikacjach 3D prawie używasz wektorów częściej niż skalarów. Wyobraź sobie, że każda liczba całkowita w Twojej aplikacji została przekazana przez odniesienie, tak że „a = 1; b = a; b ++” równa się aib równe 2. Każdy mały wektor trójskładnikowy jest kompletnym pełnym obiektem. Są one przekazywane przez odniesienie (źródło prawie połowy błędów w naszej dotychczasowej grze WebGL). Istnieją w ogromnej ilości, są przydzielane do sterty i są zbierane w śmieciach, co wywiera ogromną presję na GC, co może powodować i powoduje przerwy GC nawet w prostych grach WebGL, chyba że deweloper przeskoczy przez absurdalnie skomplikowane obręcze, aby uniknąć tworzenia nowych wektorów we wszystkich miejscach, w których logiczne jest tworzenie nowych wektorów. Nie możesz mieć przeciążenia operatora, więc masz bardzo duże i brzydkie wyrażenia do wykonywania podstawowych operacji. Dostęp do poszczególnych komponentów jest wolny. Obiekty nie są natywnie pakowane, a zatem są niezwykle wolno wpychane do bufora wierzchołków, chyba że zaimplementujesz je jako instancje Float32Array, co dezorientuje bzdury w optymalizatorach zarówno V8, jak i SpiderMonkey. Czy wspomniałem, że są przekazywane przez odniesienie? Dostęp do poszczególnych komponentów jest wolny. Obiekty nie są natywnie pakowane, a zatem są niezwykle wolno wpychane do bufora wierzchołków, chyba że zaimplementujesz je jako instancje Float32Array, co dezorientuje bzdury w optymalizatorach zarówno V8, jak i SpiderMonkey. Czy wspomniałem, że są przekazywane przez odniesienie? Dostęp do poszczególnych komponentów jest wolny. Obiekty nie są natywnie pakowane, a zatem są niezwykle wolno wpychane do bufora wierzchołków, chyba że zaimplementujesz je jako instancje Float32Array, co dezorientuje bzdury w optymalizatorach zarówno V8, jak i SpiderMonkey. Czy wspomniałem, że są przekazywane przez odniesienie?
f) Żadne wbudowane funkcje nie wymagają ani nie wymagają. Poważnie, wciąż. Biblioteki innych firm istnieją, ale prawie wszystkie mają jakiś błąd lub inny, z których co najmniej jest mylącym problemem buforowania w co najmniej Chrome, co sprawia, że faktyczny rozwój jest uciążliwy.
g) Pisanie dynamiczne. Tak, jestem gotów rozpocząć ten argument. Zaczynasz zauważać to najbardziej, gdy przestajesz pisać małe aplikacje lub strony internetowe i zaczynasz pisać duże aplikacje, w których faktycznie masz dane, które trwają dłużej niż jedno kliknięcie myszą lub cykl żądania / odpowiedzi: dodaj niewłaściwy rodzaj obiektu do tablica do przetworzenia później i awaria później z powodu brakującej metody lub elementu w zupełnie innym bicie kodu niż w miejscu, w którym rzeczywiście wystąpił błąd. Dobre czasy. Tak, Java sprawia, że wpisywanie statyczne wydaje się złe. Nie, Java / C # / C ++ nie są jedynym sposobem pisania statycznego. Wnioskowanie typu, niejawne powiązanie interfejsu itp. Zapewniają wszystkie zalety łatwego radzenia sobie i niewielkiej liczby naciśnięć klawiszy dynamicznego pisania bez wszystkich błędów. Drugi najpopularniejszy język WWW - ActionScript 3 - jest wpisywany statycznie, mimo że w przeciwnym razie jest identyczny z JS / ECMAScript. Nawiasem mówiąc, dostaję więcej awarii z aplikacji Python na moim pulpicie Fedory niż z aplikacji C / C ++ (właściwie żadna z aplikacji C / C ++ na awarii pulpitu, teraz o tym myślę). Brakujące wyjątki dla członków == o wiele łatwiejsze tworzenie i obsługa aplikacji, prawda?
h) Prędkość. Tak, ogromnie dużo wysiłku włożono w pracę wielu programistów, którzy sprawili, że JS był prawie o połowę szybszy niż kompilator C klasy niskiej, który jeden Junior Junior mógłby napisać w kilku miesięcy. LuaJIT jest w tej samej łodzi co JS pod względem podstawowych ograniczeń językowych, ale i tak radzi sobie lepiej niż każda implementacja JavaScript. Ludzie, którzy nie rozumieją, co faktycznie robią wszystkie optymalizacje JS w V8lubię twierdzić, że JS potrafi robić niesamowite rzeczy pod względem szybkości, ale w rzeczywistości wszystkie te optymalizacje są po prostu „bardzo bardzo starają się analizować kod w celu ustalenia typów zmiennych, a następnie skompilować go jak nieco opóźniony typ statyczny kompilator języka by to zrobił. ” Aha, jest śledzenie, ale wtedy śledzenie działa również na statycznie typowane języki (i działa lepiej ze względu na brak potrzeby ochrony typów w generowanym kodzie maszynowym). W rzeczywistości ani jedna z tych optymalizacji Whizbang nie została wymyślona przez JS lub dla niej; większość pochodzi z badań JVM (Java jest zła!) lub klasycznych języków OOP (prototypy są niesamowite!).
i) Nawet IntelliSense nie jest możliwy. Chcesz zobaczyć, jakie metody istnieją w zmiennej, którą masz w linii 187 foo.js w edytorze tekstu? Szkoda Prześledź kod, aż dowiesz się, gdzie został zainicjowany, a następnie prześledź kod, aby dowiedzieć się, co ma na nim jego prototyp. A potem mam nadzieję, że nie ma kodu dynamicznie zmieniającego prototyp za twoimi plecami. W rzeczywistości, po prostu uruchom go w przeglądarce i ustaw punkty przerwania, ponieważ znalezienie jakiejkolwiek użytecznej wartości w jakikolwiek inny sposób jest w zasadzie niemożliwe dla dowolnej bazy kodu większej niż witryny toy_web_app.html, których apologeci JavaScript używają do gloryfikowania łatwości i prostoty JavaScript. Niektóre edytory kodu starają się naprawdę lepiej, i prawie w pewnym sensie odnoszą sukces w naprawdę prostych przypadkach, czasami raz.
j) Brak korzyści. JavaScript nie jest nawet specjalny w porównaniu do innych dynamicznie pisanych języków. Nie jest w stanie zrobić nic interesującego, czego nie mogą zrobić także Lua, Python, Ruby itp. Żadna z implementacji JS nie jest szybsza niż LuaJIT lub PyPy ani inne zaawansowane implementacje JIT innych dynamicznych Języki. JS nie ma plusów w porównaniu z innymi powszechnie dostępnymi językami. Och, z wyjątkiem tego, że działa natywnie w przeglądarce internetowej bez wtyczki. To jedyny powód na świecie, dlaczego jest tak popularny. W rzeczywistości jest to jedyny powód, dla którego zdarzenie istnieje. Jeśli ktoś 10 lat temu pomyślał: „do diabła, upuśćmy do naszej przeglądarki istniejący dobrze zaprojektowany i dobrze ugruntowany język i niech inni zrobią to samo, zamiast zmuszać wszystkich do korzystania z tego głupiego, małego hackjoba, który wymyślił NetScape , „Internet wyglądałby dzisiaj znacznie (lepiej). Wyobraź sobie przyszłość, jeśli Chrome upuści Pythona w Chrome jako obsługiwanym języku. A właściwie wyobraź sobie: Google upuszcza C / C ++ w Chrome jako obsługiwany język (http://code.google.com/p/nativeclient/).