![]() | ![]() |
![]() |
| ![]() |
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Kako postati programer (8): Oblast vidljivosti promenljivih i funkcija
Kolekcije, oblast vidljivosti, callback...
Vrste jezika prema tipovima, coercion U JavaScriptu tip promenljive ne morate eksplicitno da zadate, već će interpreter sam zaključiti o kom tipu se radi po pokretanju programa (dinamički tipiziran jezik), a promenljive mogu da promene svoj tip u toku pisanja kôda (slabo tipizirani jezik). Pogledajte primer coercion-a, tj. automatskog menjanja jednog tipa podatka u drugi u JavaScriptu . Da biste isto to uradili npr. u Javi, jedan od načina je da ručno obavestite kompajler da se tipovi „namerno” razlikuju. To možete uraditi putem castovanja, koje govori kompajleru da tip jedne promenljive tretira kao drugi tip. Drugi način je da se koriste ugrađene funkcije u jezicima koje omogućavaju konverziju tipova. Napomena: JavaScript takođe dozvoljava da sami eksplicitno konvertujete tipove. --------------------------------------- coercion.js var a = 1 + "2"; // a postaje string "12" console.log(1 == "1"); // true dolazi do coerciona console.log(1 === "1");//false === sprecava coercion -------------------------------------- casting.java int i = 5; // primitivna prom. Integer oi = 5; // objekat double d = 6.6; d=i; // moze iz uzeg u siri tip i=d; // !ne moze i=(int)d;// mora cast-ovanje // ne postoji primitivni string String s = "a"; s = (String)i; // !ne moze cast // mora konverzija tipa s = String.valueOf(i); // nacin1 s = Integer.toString(i); // nacin2 s = oi.toString(); // nacin3
Posledica navedenog je da jezici poput JavaScripta omogućavaju da se kôd brzo napiše, bez potrebe da u startu sve bude savršeno definisano. Međutim, zbog toga interpreter jezika ne može da vas unapred upozori na eventualne greške u kôdu (provera se dešava u toku izvršavanja programa tj. runtimea). U vašem kôdu možete nenamerno da promenite tipove putem coerciona. Pošto je sve po pravilima jezika, nećete ni biti upozoreni da greška postoji, a vaš program će davati loše rezultate. U slučaju glomaznih projekata postaje izuzetno teško locirati problematičan kôd. Za veće projekte mnogi JavaScript programeri koriste biblioteke koje uvode strogu tipizaciju podataka i statičku proveru kôda (npr. koristeći Typescript, koji rešava i još nekoliko drugih problema). Tada je provera kôda moguća i pre nego što pokrenete program (compile time). Statički i strogo tipizirani jezici omogućavaju sve vrste provera kako bi vaš program imao što je manje moguće grešaka, ali zahteva dodatni napor dok kôd ne prihvati da se pokrene. Definicije koje smo objasnili nisu striktne, tako da jezici mogu biti više ili manje bliži nekoj od ovih podela. Kolekcije
U JavaScriptu su nizovi i objekti vrlo fleksibilni, lako je dodavati i brisati elemente itd. Da biste istu funkcionalnost ostvarili u jezicima C++ i Java, ne koriste se nizovi, već posebne strukture podataka – kolekcije. Na primer, slično nizu u JavaScriptu, to je Vector u C++-u ili ArrayList u Javi. Pored listi, postoje skupovi (set) koji predstavljaju kolekciju koja ne može da ima dva ista elementa (dodavanjem istog elementa skup se ne proširuje), zatim mape ili rečnici (map, dictionary), koji su slični objektima u JavaScriptu i zasnovani su na parovima „naziv” : „vrednost”, itd. Kolekcije imaju brojne ugrađene metode kojim ih uređujete ili iz njih izvlačite podatke koji vas interesuju. Vremenom ćete naučiti u kojim slučajevima da koristite koju kolekciju, a razlike su u tome da je jedna kolekcija bolja kada je bitan redosled elemenata, neka je optimizovanija ako često dodajete elemente u sredinu niza, itd. Boxing Unboxing
Foreach, Iterator Većina jezika koristi skraćenu verziju for petlje, koja je zgodna zbog bolje čitljivosti. Ukoliko vam je potreban indeks niza kroz koji prolazite da biste pristupili prethodnom ili sledećem elementu, koristite klasičnu petlju. --------------------------------- java foreach.java String[] sladoledi = new String[]{"kapri", "leni", "tigar"}; for (int i = 0; i < sladoledi.length; i++) { String sladoled = sladoledi[i]; System.out.println(sladoled);//kapri, leni.. } for (String sladoled : sladoledi) { System.out.println(sladoled);//kapri, leni.. }
------------------------------- java kolekcije.java import java.util.ArrayList; import java.util.Iterator; import java.util.List; List<String> sladoledi; sladoledi = new ArrayList<>(); //ili npr. sladoledi = new LinkedList<>(); // mozemo da prosirujemo sladolede naknadno... sladoledi.add("Kapri"); sladoledi.add("Leni"); //tri primera prolazenja kroz kolekciju Iterator<String> s = sladoledi.iterator(); while (s.hasNext()) { System.out.println(s.next()); } for (String sladoled : sladoledi) { System.out.println(sladoled); } //Java verzija 8, foreach + lambda funkcija sladoledi.forEach((sladoled) -> { System.out.println(sladoled); }); //dobijamo ispis Kapri, Leni u sva tri slucaja Oblast vidljivosti, Hoisting Ovo je jedan od osnovnih termina u programiranju. Oblast vidljivosti je na engleskom scope i, iako se donekle razlikuje od jezika do jezika, suština je ista – u kom delu kôda možete pristupiti nekoj promenljivoj (ili funkciji) koju ste definisali na drugom mestu u kôdu. Jedan od razloga što se vidljivost promenljivih ograničava u kôdu je, kao i obično, manja potrošnja resursa, manje promenljivih učestvuje u tom delu programa, pa je lakše protumačiti šta program radi, pronaći eventualne greške itd. Loša strana je što manje iskusni programeri dolaze u situaciju da im u nekom delu kôda nije dostupna promenljiva koja im je u tom trenutku potrebna (što ponekad zahteva i veće prekrajanje kôda).
Pomenućemo sada pojam hoistinga, koji je naročito izražen u JavaScriptu. Često se promenljive i funkcije ne mogu koristiti pre nego što se prvi put definišu. Međutim, interpreter JavaScripta po pokretanju programa njih automatski prebacuje na početak bloka, tako da možete prvo pozvati funkciju, iako ste tek kasnije definisali šta ona radi. Ovde je potrebno biti jako obazriv, jer ne podležu sve funkcije hoistovanju, dok hoistovane promenljive ne sadrže i vrednost koja im je u startu dodeljena. U JavaScriptu se scope promenljive ograničava na blok ako se ispred naziva napiše let, a pre verzije ES6 se ograničavala na vidljivost unutar cele funkcije sa rečju var. Ako nema ključne reči, promenljiva se smatra globalnom (JavaScript). ------------------------------- javascript hoist.js radiHoist(); // ispisuje "Da!" neRadiHoist(); // greska! console.log(x); //nije greska //ali ispisuje undefined function radiHoist() { console.log("Da!"); } var neRadiHoist = function () { console.log("Ne!"); }; var x = 5; console.log(x); //ispisuje 5 Funkcije, drugi deo
--------------------------------- vrste funkcija.js // Function Declaration function f1() { } f1(); // poziv funkcije // Named Function Expression var x = function f2() { }; x(); // poziv funkcije // Anonymous Function Expression var y = function () { }; y(); // poziv funkcije // IIFE – Immediately Invoked Function Expression (function(){ })(); Funkcija koju prosleđujete kao parametar drugoj funkciji zove se callback funkcija. Ona će biti pozvana kasnije (called back), zavisno od logike napisane u funkciji koja je prima. Funkcija koja je prima zove se funkcijom višeg reda (higher order function). Kada se funkcija stavlja kao parametar, piše se bez zagrada „()”, jer ne želite da je pokrenete, već samo prosledite. Callback funkcija može biti i anonimna funkcija. Često se anonimne funkcije nazivaju i lambda funkcije, mada je to u JavaScriptu malo širi pojam, koji nećemo pokušavati da objasnimo. Lambda funkcija je funkcija koja je prosleđena kao vrednost. Lambda može biti prosleđena kao argument nekoj funkciji, vraćena sa return iz neke funkcije ili dodeljena nekoj varijabli. Može biti anonimna, ali i ne mora. Lambde nemaju svoje this, već se ono binduje na this iz parent scopea. Primer lambdi su fat arrow („=>”) funkcije.
--------------------------------------- callback.js function callback(pozdrav) { alert(pozdrav); } function primaCallback(pozdrav, primljenCallback) { primljenCallback(pozdrav); } //nacin 1 primaCallback("zdravo", callback); //ispisuje "zdravo" //nacin2 //callback funkciju smo pisali //anonimno, direktno kao argument primaCallback( "zdravo", function(pozdrav){ alert(pozdrav); }); //ispisuje "zdravo" Closure je funkcija (ili njena osobina) koja vidi podatke van svoje oblasti vidljivosti. Closure može da vidi promenljive iz svoje roditeljske funkcije (pretpostavka je da su funkcije ugnježdene), čak i ako je roditeljska funkcija prestala sa izvršavanjem. --------------------------------- closure.js function funkcija1() { var ime = ’Svet kompjutera’; function funkcija2() { alert(ime); } return funkcija2; } var f = funkcija1(); // f postaje funkcija2 f(); //funkcija2 pamti promenljivu iz funkcije1 //ispisuje "Svet kompjutera" Funkcionalno programiranje
U funkcionalnom programiranju često se pominje (mada nije obavezno) termin „deklarativan način programiranja”, za razliku od imperativnog, kakav smo do sada koristili u primerima. Imperativnim programiranjem, kucanjem programa govorite kompjuteru šta da uradi i kako da uradi, dok je filozofija deklarativnog pristupa da samo kažete šta želite da postignete.
Postoje tri popularne metode funkcionalnog programiranja koje su našle svoje mesto i u drugim jezicima, a to su: filter, map i reduce. Filter i map su relativno jednostavne funkcije, dok je reduce komplikovaniji i moćniji, ali zbog prostora ostavljamo da ga sami proučite (filter i map mogu da se implementiraju pomoću reduce-a).
noviniz = nekiniz.filter(...).map(...) Potražite ove funkcije i u vašem jeziku po izboru (uveden je u Javu 8, ima ga Swift...). ------------------------ funkcionalni javascript.js var niz = [1, 2, 3]; var niz1 = []; var niz2 = []; // for petlja – sta zelimo i kako // zbog tog "kako" smatra se impertivnim // nacinom programiranja for (var i = 0; i < niz.length; i++) { niz1.push(niz[i] * 2); } niz.forEach(function (brojIzNiza) { niz2.push(brojIzNiza * 2); }); // map – deklarativno programiranje, // samo sta zelimo da uradimo var noviNiz3 = niz.map(function (brojIzNiza) { return brojIzNiza * 2; }); // noviNiz3 = [2,4,6] // skraceno: // map + fat arrow (lambda) function (EcmaScript6) var noviNiz4 = niz.map(brojIzNiza => brojIzNiza * 2); //filter var noviNiz5 = niz.filter(function (brojIzNiza) { return brojIzNiza > 1; }); // noviNiz5 = [2,3] var noviNiz6 = niz.filter(brojIzNiza => brojIzNiza > 1); --------------------------- javascript fat arrow.js //ES6 je doneo fat arrow funkcije //vidite koliko je moguce skratiti kod var saberi = function (a, b) { return a + b; }; var saberi = (a, b) => { return a + b }; var saberi = (a, b) => a + b; var dodaj1 = a => a + 1; //primer 1 parametar IDE, breakpoint, refactoring Za kraj malo odmora od listinga, uz spisak nekih pogodnosti koje pruža IDE i koje mi često koristimo. Jedna od njih je brzo otvaranje fajla koji vam je potreban. U slučaju NetBeansa, kada pritisnite ’Ctrl+Alt+O’, otvara se prozorčić u kojem možete da ukucate ime fajla. Dovoljno je da upišete par slova iz imena i verovatno će se lista suziti na svega par fajlova, od kojih je tu i onaj koji ste tražili. Ako držite taster ’Ctrl’ i kliknete na neku promenljivu ili funkciju, kursor će odmah skočiti na mesto na kome je ona definisana (makar to bio i drugi fajl). To je zgodno, jer ne morate da ručno skrolujete ekran ili tražite fajl. Nakon što ste videli šta vas je zanimalo, možete se vratiti „nazad” na mesto sa kog ste krenuli kombinacijom ’alt+levo’ (i ’Alt+desno’ da se opet vratite „unapred”). Ovakve skraćenice znatno štede vreme i povećavaju efikasnost rada. ’Alt+shift+F’ će automatski „srediti”, tj. formatirati vaš tekst tako da svuda bude isti stil i dobra čitljivost. Neretko ćete, posle dužeg vremena provedenog kucajući program, imati promenljive ili funkcije čiji nazivi ne odražavaju ono čemu su namenjene, jer ih u startu niste baš najsrećnije nazvali. IDE omogućava refactoring, kome je jedna od mogućnosti da napišete novo ime promenljive, a program će je sam promeniti svuda u kôdu gde je to potrebno. Ovo je dosta naprednije od klasičnog Search & replace, koji nude editori teksta, u kom možete slučajno promeniti i neki deo kôda koji ne bi trebalo. Ako se prisetite OOP i korišćenja getera i setera, mnoga radna okruženja nude automatsko generisanje ovih metoda. Da biste proveravali da li vaš program dobro radi, u samom procesu stvaranja kôda često ćete na ekranu ili konzoli ispisivati vrednosti nekih promenljivih putem print ili alert naredbe. Zatim, možete koristiti assert komande ili neki od logera kojim ćete snimiti korake rada vašeg programa u fajl (zgodno za naknadnu proveru kôda na udaljenom računaru ili uređaju). Ipak, u toku razvoja aplikacije, jedna od najkorisnijih stvari koje IDE olakšava je debagovanje i postavljanje breakpointa na liniju kôda. Kada program prilikom izvršavanja naiđe na mesto koje ste označili za prekid, izvršavanje se pauzira, a vi imate uvid u vrednosti svih dostupnih promenljivih i mnogih drugih podataka. Vrednosti promenljivih možete ručno promeniti, možete izvršavati naredne linije kôda, liniju po liniju, ili nastaviti izvršavanje programa. Na ovaj način imate detaljan uvid u rad programa i tada je lakše otkriti zašto je došlo do neke greške u kôdu. Napominjemo da proverite da li je IDE postavio program u Debug konfiguraciju i da li ste pokrenuli Debug umesto Run. Što se JavaScripta tiče, breakpoint se može postaviti i u browseru (developer tools). IDE nudi mnogo više od ovoga što smo napisali, ali je njegov značaj više nego jasan. Za kraj, IDE se može odlično povezati sa nekim od popularnih version control sistema, ali o tome u sledećem broju. Ognjen POPOVIĆ |
![]()
![]()
![]()
![]()
![]()
![]()
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() | |
![]() | ![]() |
Home / Novi broj | Arhiva • Opšte teme | Internet | Test drive | Test run | PD kutak | CeDeteka | WWW vodič • Svet igara Svet kompjutera Copyright © 1984-2018. Politika a.d. • Redakcija | Kontakt | Saradnja | Oglasi | Pretplata • Help • English | |
SKWeb 3.22 |