Nota che sto basando tutti i miei argomenti su casi d'uso reali. Gli argomenti controversi di cui non è possibile eseguire il backup con un esempio di utilizzo in applicazioni reali, complete, interessanti e utili non sono validi. Ho visto le piccole "dimostrazioni linguistiche" che hanno tutti gli altri, ho visto i post sul blog che descrivono in dettaglio come prototipi e tipizzazione dinamica rendono un piccolo esempio banale alcune righe più brevi di quanto sarebbe in C #, ma quelli semplicemente non sono rilevanti ai problemi che si incontrano nella scrittura di
codice reale anziché in micro-demo e giocattoli. Quindi ecco le mie lamentele con JS:
a) Magia "questo". Questo è questo, tranne quando questo è quello. JavaScript ti spinge a utilizzare funzioni anonime in tutto il luogo, tranne per il fatto che finiscono sempre per perdere il contesto appropriato per la variabile 'this', quindi finisci per avere un codice sciocco come "var _this = this" in tutto il luogo e quindi usarlo all'interno dei callback o di altre funzioni. Alcuni giorni giuro che il numero di funzioni che riesco a scrivere che non usano un rinominato 'this' sono in realtà inferiori al numero che lo fanno.
b) 1 + "1" - 1 = 10. Inoltre, "1" + 0 = "10". Sì, questo ha effettivamente causato bug per le nostre applicazioni, in cui i dati che si prevede fossero un numero sono stati caricati da un file JSON come stringa a causa di un bug in un'altra applicazione e il risultato non è stato buono. Tutto il nostro codice di caricamento ha dovuto essere aggiornato per aggiungere un sacco di conversioni di tipo in tutto il luogo. Quando ho bisogno che qualcosa sia un numero, voglio davvero che sia un numero, non una stringa o un oggetto o null o altro. Lua, che è molto simile a JavaScript per molti aspetti, ha risolto questo problema semplicemente non essendo ritardato abbastanza da usare lo stesso operatore per l'aggiunta e la concatenazione di stringhe.
c) Global per variabili di default. Quindi, anche se prendi l'argomento che la digitazione dinamica è semplicemente "più facile" perché non devi pensare alle dichiarazioni delle variabili, JavaScript lancia quell'argomento fuori dalla finestra facendoti mettere 'var' davanti a nuovi identificatori ovunque . E poi ti avvita in silenzio se te lo dimentichi.
d) Prototipi anziché classi. Esistono pochissime applicazioni JavaScript nel mondo reale su larga scala che non collegano il proprio sistema di classe per aggirare l'inutilità intrinseca dei prototipi nell'architettura di applicazioni di grandi dimensioni. Quelle stesse app fanno un uso minimo dei prototipi per estendere i tipi JavaScript di base e solo perché JS è stato progettato in modo così poco accurato che anche i due interessanti tipi incorporati che ne derivano mancano della metà delle funzionalità che ti aspetteresti di avere.
e) Impossibilità di creare tipi pass-by-value. Questo è un problema frequente in quasi tutte le lingue a parte C ++ / D, in realtà. Per coloro che utilizzano JavaScript per scrivere app WebGL, dai un'occhiata a tutte le librerie di algebra lineare per JavaScript. Nelle app 3D, usi quasi sempre i vettori più spesso degli scalari. Immagina se ogni numero intero nella tua app è stato passato per riferimento, in modo che "a = 1; b = a; b ++" rendesse sia a che b pari a 2. Ogni piccolo vettore a tre componenti è un oggetto completo completo. Sono passati per riferimento (la fonte di quasi la metà dei bug nel nostro gioco WebGL finora, in effetti). Esistono in grande quantità, sono allocati in heap e vengono raccolti in modo inutile, il che esercita un'intensa pressione sul GC che può e provoca pause GC anche in semplici giochi WebGL, a meno che lo sviluppatore non salti attraverso cerchi ridicolmente complicati per evitare di creare nuovi vettori in tutti i luoghi in cui è logico creare nuovi vettori. Non puoi avere un sovraccarico da parte dell'operatore, quindi hai espressioni molto grandi e brutte per eseguire le operazioni di base. L'accesso ai singoli componenti è lento. Gli oggetti non sono impacchettati in modo nativo e quindi sono incredibilmente lenti a inserirsi in un buffer di vertici, a meno che non li implementi come istanze Float32Array, che attualmente confondono la merda degli ottimizzatori di V8 e SpiderMonkey. Ho già detto che sono passati per riferimento? L'accesso ai singoli componenti è lento. Gli oggetti non sono impacchettati in modo nativo e quindi sono incredibilmente lenti a inserirsi in un buffer di vertici, a meno che non li implementi come istanze Float32Array, che attualmente confondono la merda degli ottimizzatori di V8 e SpiderMonkey. Ho già detto che sono passati per riferimento? L'accesso ai singoli componenti è lento. Gli oggetti non sono impacchettati in modo nativo e quindi sono incredibilmente lenti a inserirsi in un buffer di vertici, a meno che non li implementi come istanze Float32Array, che attualmente confondono la merda degli ottimizzatori di V8 e SpiderMonkey. Ho già detto che sono passati per riferimento?
f) Nessuna funzionalità integrata inclusa o richiesta. Seriamente, ancora. Esistono librerie di terze parti, ma quasi tutte hanno qualche tipo di bug o un altro, non ultimo il che è un problema di caching confuso in almeno Chrome che rende lo sviluppo reale un problema nel culo.
g) Digitazione dinamica. Sì, sono disposto a iniziare questa discussione. Inizi a notarlo al massimo nel momento in cui smetti di scrivere piccole app Web o pagine Web e inizi a scrivere app di grandi dimensioni in cui hai effettivamente dati che persistono più a lungo di un singolo clic del mouse o ciclo di richiesta / risposta: aggiungi un tipo di oggetto errato a un array da elaborare in seguito e ottenere un arresto in seguito da un metodo o membro mancante in un bit di codice completamente diverso rispetto a dove si trovava l'errore effettivo. Momenti divertenti. Sì, Java rende la digitazione statica malvagia. No, Java / C # / C ++ non è l'unico modo per eseguire la digitazione statica. L'inferenza del tipo, l'associazione implicita dell'interfaccia, ecc. Offrono tutti i vantaggi "facili da gestire e non molti tasti" della digitazione dinamica senza tutti i bug. Il secondo linguaggio Web più popolare - ActionScript 3 - è tipicamente statico, in realtà, sebbene diversamente identico a JS / ECMAScript. A parte questo, ottengo più arresti anomali dalle app Python sul mio desktop Fedora rispetto alle app C / C ++ (in realtà, nessuna delle app C / C ++ sul mio desktop crash, ora che ci penso). Eccezioni dei membri mancanti == molto più semplice da sviluppare e gestire app, giusto?
h) Velocità. Sì, c'è stata una quantità ridicolmente immensa di sforzi da parte di un gran numero di sviluppatori super-maledetti messi nei runtime linguistici per rendere JS quasi la metà più veloce di un compilatore C di basso livello che un singolo college universitario potrebbe scrivere in pochi mesi. E LuaJIT è nella stessa barca di JS in termini di limiti linguistici fondamentali, ma riesce comunque a fare meglio di ogni implementazione JavaScript. Le persone che non capiscono cosa fanno effettivamente tutte le ottimizzazioni di JS in V8 o similipiace affermare che JS può fare cose sorprendenti in termini di velocità, ma la realtà è che tutte queste ottimizzazioni sono fondamentalmente solo "provate molto molto duramente per analizzare il codice per capire i tipi di variabili e quindi compilarlo come un tipo statico leggermente ritardato il compilatore di language lo farebbe ". Oh, e c'è traccia, ma poi la traccia funziona anche su linguaggi tipicamente statici (e funziona meglio a causa della mancanza di protezioni dei tipi nel codice macchina generato). In realtà, nessuna di quelle ottimizzazioni di whizbang è stata inventata da o per JS; la maggior parte sono stati presi dalla ricerca JVM (Java è il male!) o dai linguaggi OOP classici (i prototipi sono fantastici!).
i) Nessun IntelliSense è nemmeno possibile. Vuoi vedere quali metodi esistono su quella variabile che hai nella riga 187 di foo.js nel tuo editor di testo? Peccato. Segui il codice fino a quando non scopri dove è stato inizializzato, quindi segui il codice per scoprire che cosa contiene il suo prototipo. E poi spero che non ci sia codice che cambi dinamicamente il prototipo alle tue spalle. In effetti, basta eseguirlo in un browser e impostare punti di interruzione, perché scoprire qualcosa di utile sul valore in qualsiasi altro modo è praticamente impossibile per qualsiasi base di codice più grande dei siti toy_web_app.html che gli apologeti JavaScript utilizzano per glorificare la facilità e la semplicità di JavaScript. Alcuni editor di codici si sforzano davvero di fare meglio, e quasi in qualche modo riescono per i casi davvero semplici, a volte, una volta.
j) Nessun vantaggio. JavaScript non è nemmeno speciale rispetto ad altri linguaggi tipizzati dinamicamente. Non è in grado di fare nulla di interessante affatto che non può essere fatto anche da Lua, Python, Ruby, ecc. Nessuna delle implementazioni JS è più veloce di LuaJIT o PyPy o varie altre implementazioni JIT avanzate di altre dinamiche le lingue. JS non ha lati positivi rispetto ad altre lingue comunemente disponibili. Oh, tranne che funziona nativamente in un browser Web senza plug-in. Qual è l'unica ragione al mondo per cui è così popolare. In effetti, è l'unica ragione per cui esiste un evento. Se qualcuno 10 anni fa aveva appena pensato "diamine, lasciamo cadere nel nostro browser un linguaggio ben progettato e consolidato e facciamo in modo che gli altri ragazzi facciano lo stesso invece di far usare a tutti questo stupido hackjob con cui NetScape ha inventato , "il Web sembrerebbe molto diverso (meglio) oggi. Immagina il futuro se Chrome rilascia Python in Chrome come lingua supportata. O in realtà, immagina questo: Google rilascia C / C ++ in Chrome come lingua supportata (http://code.google.com/p/nativeclient/).