Mračna strana JavaScript jezika
Written by Milos Aksentijevic 11 October 2019

Dark side of JavaScript

 

JavaScript je jedan od popularnijih programskih jezika. To je lagan, interpretiran i “run time” kompajliran jezik sa “first-class” funkcijama (vaše funkcije mogu biti argumenti i vraćene vrednosti kao i bilo koja varijabla i/ili bilo koji literal.)

Iako je uglavnom poznat kao skripting jezik za web strane, mnoga nepretraživačka okruženja ga koriste, kao što su Node.js, Apache CouchDB i Adobe Acrobat. On je dinamičan i predstavlja sistem baziran na događajima koji koriste petlju i single thread koji smanjuje kompleksnost i konkurentnost u programiranju. Takođe predstavlja prototype-oriented jezik baziran na prototipskom nasleđivanju (za razliku od jezika kao što su C++ I Java, koji koriste klasno nasleđivanje “class-oriented”)

JavaScript je zasnovan na prototipu, multi-paradigmi, dinamičnosti, podržavajući objektno-orijentisane koncepte kao i funkcionalni stil programiranja. U praksi predstavlja jezik za izvršenje klijentskog koda u pretraživaču.

Najveća stvar za mene, u vezi JavaScript jezikom, je koliko je lako pisati kod. Lak je za učenje i jednostavan za upotrebu, osim kada nije. Postoji mnogo “poteškoća” koje mogu da vas isprate. Nažalost, ovaj dizajn je ono što JavaScript jeziku daje mnogo loših strana ili kako ih ja volim nazvati “Mračnom stranom”.

Navedimo ih.

Tipovi

Nažalost, verovatno i najgori izbor ikada napravljen u ovom jeziku je da koristi slabe tipove podataka (weakly-typed). Varijable nemaju tip, samo vrednosti koje su unutar njih. Te vrednosti mogu biti: Object, String, Symbol, Number, Boolean, Null (da) i undefined (da, undefined je takođe tip podataka).

Čak je i smešno kada želite da testirate da li je vaša varijabla objekat morate uraditi sledeće:

if (typeof myObject === "object" && myObject !== null)

Zato što vaš Object može biti tipa Object ali takođe može biti i tipa null
Lako je pisati kod sa dinamičnim tipovima ali je takođe i lako napraviti grešku u pisanju. Da bi se izbeglo ovo, programeri koriste supersetove ovog jezika kao što su TypeScript, Flow itd…

Ne može raditi sa aritmetikom.

Brojevi u ovom jeziku su predstavljeni kao decimalni zapisi sa dvostrukom preciznošću. Što znači da nemamo integer tip. U čemu je problem? Na visokom nivou, problem je što JavaScript koristi IEEE standard za predstavljanje binarnih brojeva u decimalnoj aritmetici.

0.1 + 0.2 = 0.30000000000000004

Konverzija

Najbolnija tema o JavaScript jeziku jeste konverzija. To je ono čega svi treba da budu svesni. Setite se da JavaScript ima tipove (Brojevi, Stringovi itd…) i da varijable nisu tipizirane, dok vrednosti jesu. Kada izvršite komandu
typeof myVar === "number" vi zapravo želite da znate da li je tip vrednosti na koju ukazuje myVar broj. Ovo je jako važno shvatiti.

Sada, šta se dešava kada želite da obavite operaciju sa dve promenljive, čije su vrednosti različitih tipova?

let a = 10;
let b = "10";
let c = a + b; // ???

Decimalni broj 10 je predstavljen drugačije od stringa 10. Na primer, broj 10 može biti predstavljen u 8 bitova kao 00001010. String 10 je kodiran pomoću ASCII karaktera kao 00110000 (48) i 00110001 (49).

Da bi se izvršio pravilan proračun, JavaScript mora osigurati da su oba operanda istog tipa. Tako da JS pokušava da uradi najbolje za vas, tako da će u ovom slučaju pretpostaviti da želite da spojite decimalni broj 10 sa stringom 10, i vratiti vrednost stringa “1010”

Morate biti veoma oprezni i morate znati gde bi vam ovo moglo najviše nauditi. Evo nekoliko primera ovog problema:

[] + [] → “” // Prazan string? Ali ovo su nizovi!
[] + {} → [object Object]
{} + [] → 0 // Zašto operacija nije komutativna???
{} + {} → NaN // ???
16 == [16] → true // Niz je konvertovan u string a zatim u broj
16 == [1,6] → false // U šta je konvertovan niz?
“1,6” == [1,6] → true

Coercion
Callback pakao

Povratni pozivi su samo ime konvencije za korišćenje JS funkcija. Ne postoji posebna stvar koja se tako zove u JS jeziku, to je samo konvencija. Umesto da odmah vrate neke rezultate kao i većina funkcija, funkcije koje koriste povratne pozive zahtevaju određeno vreme da bi vratile rezultat. Reč “asinhronost” samo znači da traje neko vreme ili se dešava u budućnosti asinhrono ne ometajući izvršenje ostatka koda. Obično se povratni pozivi koriste samo kada se radi o preuzimanju stvari, čitanje datoteka, razgovor sa bibliotekama itd.. Ugnježdavanjem ovih poziva će se stvoriti problem za vas bez poznavanja kada će koja funkcija da se izvrši.

Rešenje za ovo je korišćenje promises, generators i async await.

Globalne promenljive

Zašto treba izbegavati globalne promenljive i zašto su one loše?
Prestavljaju nešto dodeljenog (alociranog) prostora u memoriji koji nećete moći da povratite bez da ih ekspricitno poništite pozivom

window.x = null

To uključuje neželjene efekte u vašim funkcijama koje će to iskoristiti, što čini kod složenijim za razumevanje. Drugi ljudi su takođe mogli da koriste ovu promenljivu za biblioteku. Najgore od svega, mogao bi se ubrizgati zlonamerni kod koji bi učinio da vaš kod prestane da radi ili u najgorem slučaju procure osetljive informacije. Teško je testirati globalne varijable jer su globalne, a njihovo korišćenje u ostatku koda teško odrediti.

Postoji mnogo načina da se izbegnu globalne promenljive kao što su closures i IIFE. Uvek koristite let i const kada deklarišete promenljivu, ako niste sigurni koristite strict mode.

Scope neslaganja

Programer treba da bude svestan upotrebe scopa. Pogotovo kada se radi o ključnoj reči “this”. Svaka funkcija, svaki objekat ima svoj vlastiti scope, tako da neke varijable i druge funkcije nisu dostupne u nekim delovima koda. Zato morate biti oprezni u pogledu unutrašnjeg i spoljašnjeg Scope-a nekog objekta ili funkcije.

Govoreći o ključnoj reči “this”, programeri često prave greške koristeći je u arrow funkcijama.

const foo = () => {
let bar = 10;
console.log(this)
}

foo() -> // this će se odnositi na globalni (spoljni scope).
Razlog zašto se ovo dešava je taj što arrow funkcije nemaju this.

Podrška za ostale verzije JavaScript jezika

Postoji dosta grešaka koje su popravljene i pokrivene u novijim verzijama ovog jezika. Međutim da bi imali podršku za starije biblioteke i skripte, pretraživači podržavaju i starije verzije, tako da stari web sajtovi mogu da “žive”.

Savet i rešenje za ovo je korišćenje najnovijih verzija kao što su ES6+ sa ‘use strict’ direktivom na vrhu vašeg koda ili na vrhu tela funkcije koju pišete.

Kada se nalazi na vrhu skripte, čitava skripta radi na “moderan” način. ‘use strict’ direktiva prebacuje JavaScript pokretač na ‘moderan’ režim menjajući ponašanje nekih ugrađenih funkcija i vrši dodatnu optimizaciju vašeg koda prilikom kompajliranja. Ovo omogućava nekoliko novina u jeziku kao sto su klase i moduli. Striktni mod podržavaju svi moderni pretraživači. Bez ovog moda sve će i dalje raditi ali neke funkcionalnosti će se ponašati na stari “kompatibilni” način. U principu više želimo moderno ponašanje.

Volim JavaScript jezik i koristim ga svakodnevno. Ali to ne znači da ne postoje neke zaista strašne greške u samom jeziku. Mislim da nisam ni približno pokrio sve loše stvari i kako ih izbeći ali želim da se ova lista ažurira što je više moguće, tako da nemojte se ustručavati da date neke povratne informacije kao i teme koje bi želeli da pokrijem. Hvala vam.

BACK

LEAVE A COMMENT

JOIN THE MAILING LIST