Šta je novo?

JavaScript pitanje

codejan

Čuven
Učlanjen(a)
06.07.2004
Poruke
256
Poena
620
Moja oprema  
CPU & Cooler
Intel Core i5-3470 quad core
Matična ploča
Gigabyte GA-P75-D3
RAM
Kingston 12GB DDR3 HYPER blu
GPU
EVGA GeForce GTX 260 896MB DDR3
Storage
Hitachi 1TB, EXRAM 512GB SSD
Zvuk
Creative Live! 5.1
PSU
Thermaltake SMART RGB 700W
Kućište
MS MidiATX
Monitor
BENQ FP91G+, HP W19
Miš & tastatura
Logitech MX400
Ostale periferije
neo SW-H55
Laptop
Lenovo ThinkPad T450s, ASUS eeePC 1001HA
Tablet
Lenovo TB-8505X
Mobilni telefon
Xiaomi Redmi 10 2022
Pametni uređaji
Denver BFH-17, Xiaomi TV Stick 4K
Pristup internetu
  1. ADSL
Pozdrav postovanoj zajednici,

Imam jedno pitanje iz JavaScript-a.

Zasto JavaScript ne referencira niz unutar funkcije, kada taj referencirani niz prepisem drugim, vec samo kada menjam polja tog niza unutar funkcije koja ima referencu na taj niz?

Znam da objekti i nizovi salju referencu na svoje podatke funkcijama, pa sam prvenstveno hteo, iz radoznalosti, da saznam da li i stringovi salju referencu na sebe funkciji. Pretpostavljam da je situacija sa nizovima drugacija iz razloga sto ne moze direktno da se menjaju clanovi stringa, ali nisam sto posto siguran.

Kod
Kod:
<script type="text/javascript">

var ja = [1,2,3];

function abc(neko){
	neko = [4,5,6];
}

abc(ja);

alert(ja.toString());

</script>

Dobijam rezultat 1,2,3, a trebao bih, po meni, 4,5,6!

Ovaj kod radi ispravno, opet, po meni:

Kod
Kod:
<script type="text/javascript">

var ja = [1,2,3];

function abc(neko){
	neko[1] = 7;
}

abc(ja);

alert(ja.toString());

</script>

I ispisuje 1,7,3
 
Izvini, firefox mi je pukao u trenutku kada sam pritisnuo "pošalji odgovor", posle pisanja gomile teksta, pa ću ovog puta morati da budem kraći da ne bi olupao monitor :d Prvi put da mi se ovo desi... Nego...

U pravu si, funkcije primaju referencu a ne vrednosti odjekata, pa bi trebalo da se promenom te promenljive menja i originalna globalna promenljiva, što se i dešava u slučaju menjanja elementa promenljive.
Kod:
function abc(neko){
    neko = [4,5,6];
}
Problem nastaje kada pokušaš da promeniš samu promenljivu, odnosno vrednost same promenljive. U ovom slučaju znak jednakosti pravi novu promenljivu ("prebriše" - overwrite argument funkcije) umesto da menja vrednost stare. Da bi se uverio da je to tako, u gornjem kodu, vrati vrednost promenljive neko (return), i videćeš da vrednost jeste "4,5,6", samo što je to sada nova promenljiva. Evo ilustracije: http://jsfiddle.net/z5zLT/

Ista je situacija i sa objektima. Ako pokušaš da promeniš bilo koji deo objekta, polje, properti, kako god želiš da ih zoveš, znak jednakosti ne pravi novu promenljivu tako da će se promeniti i originalna globalna promenljiva. Ali ako pokušaš da promeniš ceo objekat, znak jednakosti u stvari pravi novu promenljivu. Ilustracija: http://jsfiddle.net/z5zLT/1/

Razmisli, kako bi inače napravio novu promenljivu unutar funkcije :)
Kod:
([B]var[/B] može i ne mora, to je već druga priča) naziv_promenljive = nešto

To mu dođe osnovna definicija kreiranja varijable, a to je upravo ono što si ti uradio sa
Kod:
neko = [4,5,6];
 
Sjajan odgovor. Hvala. :)

Pretpostavljam da stringovi referenciraju sebe u funkciji, ali zbog toga sto ne mogu da se menjaju njihovi atributi (slova) u istoj promenljivoj, bezpredmentno je razmiljsati o njima isto kao i o nizovima i objektima unutar funkcija sa svojim referencama. Ili da?
 
Baš tako, primitivni tipovi su "pass by value" (uključujući i string), a objekti su "pass by reference", a baš iz razloga što su stringovi "immutable" (ne možeš ih promeniti) nikako ne možeš promeniti string promenljivu koja je prosleđena funkciji (možeš napraviti novu promenljivu koja sadrži delove originalnog stringa, odnosno i dalje možeš "čitati" slova iz stringa tako što mu pristupaš kao nizu, ali ne možeš menjati slova, tako da će originalni string uvek ostati ne promenjen). Ilustracija: http://jsfiddle.net/mBdqM/
 
Hvala na opseznom odgovoru. Ali, eto, ako ja mogu i tebi jednu sugestiju da uputim apropo ovog primera i pristupanja stringu kao nizu, u knjizi ne preporucuju takvu upotrebu indeksiranja stringa kao sa nizom. E sad da me pitas zasto, ne znam vec tako pise... :) Pretpostavljam da je to zato sto mozda taj oblik funkcionalnosti nece raditi u buducnosti...
 
Ok, to sam dao samo kao primer da pokažem da se vrednost stringa može čitati ali ne i menjati, mada ne znam zašto autor knjige ne preporučuje. U svakom slučaju čitanje jednog slova nije preterano korisno, već se za manipulaciju stringova uglavnom koriste string funkcije. Recimo, isti efekat čitanja jednog ili više slova se uglavnom radi sa funkcijama substring() ili substr().
 
Ok, hvala.
 
Imam jos jedno pitanje. Radi se o blokovima closure.

Ne mogu da razumem ovaj kod, ali on radi ok:

Kod:
uniqueID = (function (){
	var id = 0;
	
	return function (){ return id++;};


})();

alert(uniqueID());
alert(uniqueID());
alert(uniqueID());

Ispisuje 0, 1 i 2, ali meni nije jasno kako "var id = 0" ne prepise i vrati vrednost na 0 promenljivu id svaki put kad se pozove?

I jos jedno potpitanje, ako se prave stekovi poziva (otprilike tako ja pokusavam da razumem ovu funkciju), zasto prvi rezultat nije 1?
 
Ok, mogu sam sebi i drugima koje ovo interesuje odgovoriti: spoljna anonimna funkcija "takoreci" setuje sve komande do kraja reci return. Pozivanje uniqueID(), poziva tu funkciju i "ozivljava" deo komande posle reci return i tako setovani id pamti u "zivoj" anonimnoj unutrasnjoj funkciji.

Prakticno, pozivanjem uniqueID funkcije se pokrece kod unutrasnje anonimne funkcije i stavlja u senku kod spoljne anonimne funkcije.

Evo i koda koji to potkrepljuje:

Kod:
function makefunc(x){
	return function(){return x};
	
}

alert(makefunc(5));

Ispisuje "function(){return x};".

Kod:
function makefunc(x){
	return function(){return x};
	
}

alert(makefunc(5)());

Ispisuje 5.
 
Poslednja izmena:
I jos jedno potpitanje, ako se prave stekovi poziva (otprilike tako ja pokusavam da razumem ovu funkciju), zasto prvi rezultat nije 1?

Zato što id++ nije isto što i ++id :) Kada je ++ posle promenljive, to znači prvo izvrši šta god već treba da se izvrši, pa tek onda inkrementuj promenljivu. Kada je ++ pre promenljive obrnuto je. Promenljiva se prvo poveća za 1 pa se onda izvrši komanda. U tvom slučaju funcija se "vrati" (return) pre nego što se broj poveća. To je tako u većini jezika. Ilustracija: http://jsfiddle.net/fjqpV/
 
Zato što id++ nije isto što i ++id :) Kada je ++ posle promenljive, to znači prvo izvrši šta god već treba da se izvrši, pa tek onda inkrementuj promenljivu. Kada je ++ pre promenljive obrnuto je. Promenljiva se prvo poveća za 1 pa se onda izvrši komanda. U tvom slučaju funcija se "vrati" (return) pre nego što se broj poveća. To je tako u većini jezika. Ilustracija: http://jsfiddle.net/fjqpV/

Znam za to. :)

Nego sam ja mislio da kad se u literalnom konstruktoru funkcije pozove funkcija (sa dvema krajnjim zagradama), da ce se izvrsiti kod posle return i time vec u samo konstruktoru literalu povecati vrednost id-ja. Eto, nisam znao za ovo, kako bi ga ja nazvao, "zamracenje koda"! :D
 
Poslednja izmena:
Zasto se u oblasti imenskih prostora za zaglavlje koda koristi naredba var i najvisi objekat (npr. com)?

Zar to nece prepisati svu funkcionalnost koda navedenog u odredjenom imenskom prostoru i postaviti taj najvisi objekat com na undefined, kao i sve ostale podobjekte?

Kod:
var com; // Konkretno ova naredba ovde. Zasto i kako?

if (!com || !com.dejancolic || !com.dejancolic.Class)
    throw new Error("com/dejancolic/Class.js nije ucitan");

...

Po mojoj logici bi ovaj uslov bio true u prvom ispitivanju jer je com u gornjoj naredbi setovan na undefined!
 
Poslednja izmena:
Opet cu sam sebi i ostalima odgovoriti:

Kod:
var i = 1;

var i;

alert(i);

Ispisuje 1.

Odnosno, ponovno redeklarisane vec inicijalizovane promenljive nece ponistiti svoje svojstvo (suprotno mojim dosadasnjim iskustvima!).
 
Poslednja izmena:
Jos jedno pitanje:

Kod:
var i = new RegExp("(\\d{5})(\\w{3})", "g");
var j = "12345asd";	

var result=function (){
	

	return i.exec(j);
};

alert(result); // Ispisuje: function (){return i.exec(j);}

if ((typeof result() == "object")&&(result() instanceof Array)) alert("Array"); // Ne okida??
if ((typeof result == "function")&&(result instanceof Function)) alert("Function"); // Okida

alert(result()); // Ispisuje: "12345asd","12345","asd"

if ((typeof result() == "object")&&(result() instanceof Array)) alert("Array"); // Okida
if ((typeof result == "function")&&(result instanceof Function)) alert("Function"); // Okida

Zasto mi za prvi uslov ne ispisuje Array, a treci ispisuje. Zar nije svejedno gde pokrecem funkciju?
 
Uh bre mnogo pitaš. Gde li nalaziš ove zavrzlame :)

Rezultat koji dobijaš je u suštini zanimljiva koincidencija više stvari. Sledi još jedan komplikovan odgovor.

Regexp objekat ima interni pointer koji pokazuje na poslednju ispitanu poziciju (karakter) u stringu koji se ispituje. Kada pozoveš exec() nad regexp objektom, ako postoje match-evi u traženom stringu, ovaj pointer se pomera na poslednji karakter match-a i pri sledećoj proveri počinje od pointer-a pa na dalje. E sad...

U tvom konkretnom slučaju, exec() pronalazi ceo traženi string, odnosno ceo traženi string je match, i result() vraća array. Posle poziva exec() regexp interni pointer se pomera na poslednje slovo u match-u što je ujedno i poslednje slovo u celom string-u, tako da kada pozoveš exec() po drugi put, result() vraća null, odnosno nema rezultata (jer u suštini ispituje string "d" jer je to poslednji karakter u match-u). Posle drugog poziva result(), pointer se resetuje jer je došao do kraja string-a, tako da treći uzastopni poziv result() ponovo vraća array jer je pointer pri pozivu bio na nuli. E sad obrati pažnju, u tvom kodu dešava se sledeće:

Prva linija sa uslovima u tvom kodu poziva result() dva puta. Posle prvog poziva, rezultat result() je array (što je ujedno i object, tako da typeof result() == "object" prolazi). E sad, pri proveri da li je instanca array, prvo se result() ponovo! izvrši, tako da je rezultat sada null! (što naravno nije array). Idemo dalje...

Druga linija sa uslovima nije bitna jer ne poziva result() već samo ispituje samu promenljivu tako da je preskačem.

Sledeće što se dešava je još jedan poziv result(). Pazi, pre ovog poziva, result() je pozvan dva puta, što je resetovalo interni pointer, tako da je sada pointer na nuli i ovog trećeg puta result() vraća array kao što alert i ispisuje, i ponovo je pointer na poslednjem karakteru i pri sledećem pozivu result() će vratiti null.

Treća linija sa uslovima. Pazi sad... Prvi uslov ispituje da li je result() tipa object. Pošto smo rekli da će sledeći poziv result() vratiti null, baš to se i desi. Tako da ovaj uslov ispituje da li je null tipa object... Što u javascript-u i jeste! (uradi alert(typeof null) i videćeš). Sledeći uslov u istoj liniji po ko zna koji put poziva result() i ispituje da li je rezultat array. Pošto je pre ovog poziva rezultat bio null, sada je pointer resetovan i ovog puta će result() vratiti array! tako da uslov prolazi.

Uh, nadam se da znaš šta radiš, jer je ovo u svakom slučaju bespotrebno zakomplikovano. Ovo bi pre mogao da bude zadatak na nekom ispitu nego realan kod u nekom projektu.


Zaboravih da dodam, ako ti je iz bilo kog razloga potrebno da baš ovaj kod proradi, ono što treba da uradiš je da resetuješ interni pointer regexp objekta svaki put pre pozivanja exec(), odnosno da ponovo napraviš regexp objekat:

Kod:
var j = "12345asd";	

var result=function (){
    var i = new RegExp("(\\d{5})(\\w{3})", "g");
    return i.exec(j);
};

I čisto ako te zanima, ovaj interni pointer se zove lastIndex i čisto da dokažem da je u ovome problem, umesto kreiranja novog regexp objekta svaki put, možeš i ručno resetovati ovaj property:
Kod:
var i = new RegExp("(\\d{5})(\\w{3})", "g");
var j = "12345asd";	

var result=function (){
    i.lastIndex=0;
    return i.exec(j);
};
 
Poslednja izmena:
Ok, a ja sam se ubio od ispitivanja (na mom lokalu) koja je to vrsta objekata: pa nije null, pa nije niz, pa jeste niz itd... Setalo me je jedno sat vremena, a nisam uvideo da exec drzi povodac! :D
 
Pozdrav, pokusavam vec neko vreme da zamenim konstruktore objekata i neide mi za rukom. U prilogu sam dao prost primer onoga sto zelim da se dogodi. Hvala.

Kod:
<script type="text/javascript">

function Ja(){

	this.ime = "Dejan";
}

function Ti(){
	
	this.ime = "Ivan";
}


Ja.prototype.constructor = Ti;
neko = new Ja();


alert(neko.ime); // Daje Dejan, a ja ocekujem Ivan

</script>
 
Koliko sam uspeo da saznam, nemoguce je promeniti konstruktor objekta, vec je moguce da samo taj kosntruktor nasledi druga svojstva odredjenog objekta:

Kod:
<script type="text/javascript">

function Ja(){

	this.ime = this.ime || "Dejan";
}

function Ti(){
	
	this.ime = this.ime || "Ivan";
}


Ja.prototype = new Ti();
neko = new Ja();


alert(neko.ime); // Daje Ivan

</script>

Razlog za logicku disjunkciju u dodeli svojstva je taj sto bi poziv new Ja() zasenio nasledjena svojstva koja pruza new Ti().
 
Nazad
Vrh Dno