Hetkel on probleem selles, et for..in käivitub vaid esimesel korral. Kui asendaksid rea
for ( var i in lopp )
reaga
for( var i=lopp.length-1;i>=0;i--)
siis peaks asi tööle hakkama.
for..in konstruktsioon on siinkohal niikuinii täiesti vale, kuna see on mõeldud objektide meetodite/omaduste loendamiseks, mitte näiteks massiivi elementide või veel vähem stringi üksikute sümbolite lugemiseks. Seda on küll mõningal määral võimalik teha, kuna JavaScript üritab sisendväärtuse teisendada alati konteksti sobivaks, kuid tulemus võib olla (nagu siingi juhul) üsna ootamatu.
Kui mul on objekt kujul
var objekt = {
meetod: function(){},
omadus: "väärtus"
}
siis teada saamaks, milliseid omadusi/meetodeid objekt sisaldab, for..in täiesti omal kohal
for(var i in objekt) alert(i); // "meetod", "omadus"
Kõikidel muudel juhtudel, isegi kui for..in kasutamine on reaalselt võimalik, tasub kasutada siiski muid konstruktsioone (for, while jne). Seda juba kasvõi seetõttu, et tõenäoliselt soovitakse saada tulemusi ikkagi "järjest" (ehk siis 0,1,2,...N), kuid for..in puhul ei ole selline järjestus kunagi garanteeritud! Antud tsükkel ei järjesta automaatselt väärtusi võtme järgi, vaid loeb neid ükshaaval võtmeid arvuti mälust, kus need ei pruugi olla sugugi soovitud järjekorras (kuigi 99% juhtudest need seda siiski on).
Samuti on probleemiks eriti just massiivide juures, et for..in loeb sisse mitte ainult massiivi numbrilise võtmega elemendid, vaid ka massiivi kui objekti meetodid ja omadused. Sellisel viisil on nähtavad ainult kasutajate lisatud omadused/meetodid ning reeglina neid polegi seatud, kuid kolmanda osapoole teegid võivad vabalt olla midagi näiteks massiivi prototüüpobjekti lisanud ja need lisandused kanduvad edasi igasse massiivi, mida üritatakse for..in lausega loendada.
Näiteks kui mõni teek on lisanud massiividele juurde omaduse massiiviPikkus, mis tagastab massiivi elementide arvu:
Array.prototype.massiiviPikkus = function(){return this.length}
Mida saab kasutada nii:
var massiiv = ["a","b","c"];
alert(massiiv.massiiviPikkus()); // 3
Siis massiivi elementide loendamise for..in abil tuleb ka see meetod teiste massiivi elementidega võrdselt esile:
var massiiv = ["esimene element", "teine element", "kolmas element"];
for(var i in massiiv){
alert(i); // 0, 1, 2, "massiiviPikkus"
}
Kui aga skript tahab midagi selliselt loendatud massiivi elementidega teha, näiteks väljastada ekraanile, on tulemus kõike muud, kui soovitud:
alert(massiiv[0]); // "esimene element"
...
alert(massiiv["masiiviPikkus"]); // "function(){return this.length}"
Näite puhul väljastataks seega ekraanile kõik massivi elemendid ja lõpuks veel meetodi massiiviPikkus source.
Seega kokkuvõttes - for..in on reeglina mõistlik kasutada AINULT objekti meetodite/omaduste loendamiseks ja ei millekski muuks. Kõikidel teistel juhtudel tasub kasutada "vana head" tavalist for lauset või siis mõnd sarnast alternatiivi.
Edit: Lühike variant funktsiooni kirjeldamiseks
function hajuta(tekst){
var varvid = ["#000", "#333", "#666", "#999", "#CCC", "#DDD"],
i = tekst.length;
document.write(tekst.replace(/(.)/g,function(a,b){
return --i>=6?b:'<span style="color:'+varvid[5-i]+'">'+b+'</span>';
}));
}
hajuta("See on mingi lause");