![]() Sveikųjų skaičių žaidimai JavaScipt turi automatinį tipų pakeitimą. Tačiau kartais tai sukelia sumaištį. Pvz., Su tokiu patarimu imkime naują pavyzdį. Tarkim, kad kažkokių operacijų su data dėka, ištraukėme teksto
eilutę, kuri turi dienos (mėnesyje) reikšmę (tarkim, 01, 02, ..., 29, 30, 31), kuri priskirta kintamajam
diena. Tada panagrinėkime tokį pavyzdį: Dalybos veiksmas reikalauja, kad operandai būtų skaitinės reikšmės, todėl prieš tai tekstinę eilutę su dienos reikšme pakeitėme jos skaitine reikšme. Ir visa tai puikiai veikia, bet ... ne visada! Kai kuriais atvekais gaunama dalybos iš nulio klaida (arba "begalybė"). O kodėl toliau ir bus aiškinama.
parseInt funkcija skirta teksto eilutei paversti skaitine reikšme. Be to, ji leidžia naudoti kitokį nei 10
skaičiavimo pagrindą. Pvz., galima įvesti dvejetainius skaičius: Be abejo, tai labai patogu. O jei nenurodomas pagrindas naudojamas 10 - nebent tekslo eilutė prasideda 0x (tada imama šešioliktainė reikšmė) arba 0 (aštuntainiam pagrindui). Šie susitarimai turi ilgą istoriją ir siekia kompiuterių ištakas. O tai reiškia, kad tokie prefiksai gali tapti pavojingais. Pvz., 01 bus laikomas kaip aštuntainė reikšmė 01, kuri, vienok, nesiskiria nuo dešimtainio 1. Tačiau problema kyla su 08, nes 8 nėra leistinas aštuntainis skaitmuo (kaip ir 09 atveju). Taisyklė yra tokia, kad nesant neleistiniems simboliams, atpažinimas sustoja ties pirmu tokiu simboliu tad 08 ir 09 atveju gražinama reikšmė 0. Tai ir yra priežastis, kodėl minėtas pavyzdys gražina dalybos iš nulio klaidą. Dar paaiškėja, kad parseInt yra kiek skirtingai realizuojamas skirtingose naršyklėse. Pvz., IE9 netaiko 0
prefikso taisyklės 08 ir 09 atveju ir skaičių laiko esant dešimtainiu. Vis tik, parseInt funkciją reikia naudoti
atsargiai. Minėtame pavyzdyje problemą išsprendžia pagrindo nurodymas, t.y. Truputis magijos: perrašome parseInt funkciją Minėta, kad naujausia ECMAScript 5 versija atsisakė pirmąjį 0 laikyti aštuntainio skaičiaus požymiu, tačiau JavaScript versija dar nėra visuotinai paplitusi. Tad vienas iš galimų sprendimų šio neaiškumo pašalinimui būtų pakeisti parseInt funkciją. Laimei, tai nėra sudėtinga ir kartu tai puikus pavyzdys, pailiustruojantis, kokia lanksti yra ši kalba. Tačiau pradžioje reikia trupučio paaiškinimų. parseInt yra globalioji funkcija, o tai reiškia, kad ji yra globalaus objekto, dažniausiai windows, metodas. Tad ją kviesti galime Tačiau naudojant su this, reikia būti tikriems, kad nesame konstruktoriaus funkcijoje arba tai gali reikšti nuorodą į ką nors kita, o ne globalų objektą. O tada, kaip bet kurio metodo atveju, galima ją apibrėžti kitaip priskiriant jai anoniminę funkciją, t.y. taip: Ir po tokio jos apibrėžimo, visi parseInt panaudojimai reikš kreipinį į mūsų funkciją. Belieka parašyti pataisytą šios funkcijos versiją kas neatrodo labai įdomu ir tarytum tėra laiko švaistymas, nes tenorime tik nežymiai pakeisti šios funkcijos veikimą. Idėja išsaugoti nuorodą į originalią parseInt funkciją, kuri būtų kviečiama tada, kada tai daryti saugu. Tuo tikslu parašome set_new_parseInt funkciją: set_new_parseInt = function () { if (parseInt("010") === 10) return; var savedOriginal = parseInt; parseInt = function(n,r) { if (r === undefined) { n = n.replace(/^s*/, ""); if (n.substr(0,2) === "0x") { r = 16; } else { r = 10; } } return savedOriginal(n, r); }; } Dabar išbandykime: set_new_parseInt(); alert(parseInt("0xFF")); // pateikia 255 alert(parseInt("111", 2)); // pateikia 7 alert(parseInt("023")); // pateikia 23 alert(parseInt("09")); // pateikia 9 Taigi, kaip matote, funkcija parseInt veikia puikiai ir netgi tuo atveju, kai jai perduodamas problematiškoji reikšmė 09. Beliko paaiškinti kelis aspektus.
Pirmiausia yra patikrinama, gal parseInt funkcija jau veikia taip, kaip tikimės. Tuo tikslu ji iškviečiama ir patikrinamas jos rezultatas. Jei funkcija jau ignoruoja pradinį 0, tai nieko nedarome ir tiesiog grįžtame iš mūsų funkcijos. Tai atlieka: Tada lokaliame kintamajame įsimename nuorodą į originaliąją parseInt funkciją: Toliau seka parseInt patobulinimas. Mums tereikia tikrinti ir patikslinti atvejį, kai antrasis parametras yra nenurodytas. Tai nustatome naudodami Toliau belieka patikrinti, ar parametras neprasideda 0x (šešioliktainio skaičiaus požymis) ir nurodyti, koks turi būti skaičiavimo sistemos pagrindas (16 ar 10). Ir tada iškviečiama originalioji parseInt funkcija (jau su patikslintu antruoju parametru). Paprasta, ar ne? Visa magija tame, kad įmanoma iškviesti lokaliajame kintamajame įsimintą nuorodą į originaliąją parseInt funkciją. Tai užsklendimo (angl. closure) savybė, kai naujai apibrėžta (parseInt) funkcija gali naudoti funkcijos, kurioje ji buvo apibrėžta, lokaliuosius kintamuosius. Puikiai išsprendėme problemą! Va! ... tik nereikia užmiršti, kad prieš naudojant patobulintą parseInt, būtina (!) dar iškviesti ir set_new_parseInt(). Tad būtų truputį geriau, jei galėtume taip apibrėžti naująją parseInt, kad jinai savo pirmojo panaudojimo metu save pačią modifikuotų. Tad mūsų laukia naujas magijos seansas. Mat tiesmukiškas bandymas
parseInt = function (n, r) {
if (parseInt("010") === 10) return;
var savedOriginal = parseInt;
return (function(n,r) {
if (r === undefined) {
n = n.replace(/^s*/, "");
if (n.substr(0,2) === "0x") {
r = 16;
} else {
r = 10;
}
}
return savedOriginal(n, r);
});
} ()
Visa magija yra tuose skliausteliuose (), kurie (pačioje pabaigoje ir yra išryškinti raudonai) užbaigia funkcijos apibrėžimą. Jie priverčia iškart vykdyti funkciją ir gražinti nuorodą funkciją, kurią ką tik parseInt< apibrėžė. Jei tų skliaustelių gale nebūtų, gautumėte pranešimą apie steko persipildymą galite patys pasvarstyti., kodėl taip nutinka. Toliau, vėl panaudojamas tas pats užsklendimo (closure) mechanizmas, užtikrinantis originaliosios funkcijos panaudojimą. Puiku! Pabandykite ir pamatysite, kaip nuostabiai tai veikia (šįkart nereikia jokių papildomų parseInt iškvietimų). Vienintelis trūkumas, tai papildomas procesoriaus kaitinimas, nes dabar kiekvieno kreipinio į parseInt metu vyksta perteklinis patikrinamas, ar funkcija korektiškai veikia ( if (parseInt("010") === 10)). Šis pavyzdys puikiai pailiustruoja JavaScript kalbos funkcinius ir dinaminius aspektus. Šią techniką galima panaudoti bet kurios funkcijos patobulinimui išlaikant galimybę iškviesti ir ankstesniąją tos funkcijos versiją. Nors ... bendruoju atveju tai ir nėra pati geriausia idėja ir ją panaudoti tereikia, kai to tikrai reikia.
Pastaba: Pabaigoje tiesiog priminsime, kad trys lygybės (===) reiškia, kad simbolių eilučių palyginimo metu nereikia atlikinėti jų konversijų į sveikus skaičius [ ir jei Ankstesnės "Advanced HTML" skyrelio temos:
| |