![]() JavaScript kitoniškumas JavaScript yra unikali tarp kitų kalbų. It ji yra pilna programavimo kalba, leidžianti spręsti įvairius uždavinius. Objektai, o ne klasės Tačiau labiausiai programuotojus suerzina tai, kad joje nėra klasių. O kitos kalbos, ne tik turi klases, bet ir griežtą tipų kontrolę, Tačiau to visai nereikia JavaScript kalbai! Juk JavaScript turi objektus kai kuriuos pateikiamus, tačiau, daugiausia, susikuriamus. Ir ne pirma kuriate klasę, kurią po to inicializuojate, o paprasčiausiai imate ir kuriate objektus. Pvz., var oMano = { }; oMano.naujasMetodas = function() { }; oMano.naujaSavybe = "duomuo"; O galima naudoti new Object konstrukciją. Ir visai nesvarbu, kaip sukuriamas objektas, - ir nėra poreikio klasės sąvokai. Bet kodėl taip dažnai bandoma į JavaScript įtraukti klasės idėją? Tam yra trys priežastys. Pirma, klasės aprašas naudojamos skirtingų objekto kopijų (instances) sukūrimui. Antra, klasė naudojama tipų apibrėžimui, o trečia klasės pagalba apibrėžiamas paveldimumas. Visos trys yra visiškai nebūtinos ir yra skirtos aprašo dalies atskyrimui nuo vykdymo. Interpretuojamoms kalboms tam nėra poreikio. JavaScript kalboje objektai sukuriami vykdymo metu. Peržiūrėkime tas tris klasių priežastis. Dėl daugelio objektų kopijų, JavaScript kalboje dauguma objektų yra vienišiai ir todėl nebūtinas mechanizmas jų daugelio kopijų kūrimui. O paprasčiausias būdas daugelio kopijų sukūrimui panaudoti gamyklinę funkciją. Juk jei yra objektai, tai galima įsivaizduoti, kad yra gamyklų objektai, kuriantys kitus objektus. Pvz., manoObjektuGamykla = function () { var oLaikinasObjektas = { }; oLaikinasObjektas.manoMetodas = function() { alert(oLaikinasObjektas.manoSavybe); } ; oLaikinasObjektas.manoSavybe = "duomuo"; return oLaikinasObjektas; } var o1 = manoObjektuGamykla(); var o2 = manoObjektuGamykla(); Pastaba: yra keletas būdų objektų gamyklos sukūrimui. O dabar dėl tipų. Tačiau JavaScript turi objektus su metodais ir savybėmis, kurie įtraukiami vykdymo metu. Tai dinaminė kalba, kuri sukonstruota taip, kad joje tipo sąvoka yra beprasmė. Ir tai gerokai supaprastina kalbą, nes nereikia rūpintis hierarchijomis, tipų suderinamumu ir konversija ir pan. Pagaliau paveldimumas. Bet jei nėra tipų, nėra ir tipų hierarchijos. JavaScript kalboje paveldimumas pakeičiamas pragmatiškai įtraukiant ar pakeičiant metodus ir savybes. Trumpai tariant, JavaScript gyvuoja vykdymo metu! Dygios eilutės JavaScript viskas yra objektai ir joje labai lengva įtraukti funkcijas, manipuliuojančias pagrindiniais
duomenų tipais Pvz., net paprasčiausia eilutė yra objektas, todėl galime parašyti (kas prieštarauja visiems
programavimo dėsniams): Turėdami tai mintyje, pasirašykime trumputę funkciją, palyginančią, ar nurodyta eilutė yra lygi norimai teksto eilutei: function arTaip(eil) { return eil === "taip"; } Pirmiausia, tai yra tikslus tikrinimas eilutė privalo būti lygi tik taip ir jokiais būdais nekonvertuojama į
taip iš kitų duomenų tipų. Tad nėra didelio skirtumo tarp == ir === naudojimo juk eilutė yra arba nėra
eilutė, ir ji lygi arba nelygi taip. Tad galime naudoti ir function arTaip(eil) { return eil == "taip"; } Tikėdamiesi tų pačių rezultatų, nors bendrai priimta laikyti, kad reiktų vengti == ir !=, tad pirmas variantas labiau vartotinas. Taip, tačiau toji funkcija buvo naudota daug didesnėje programoje, - ir buvo pastebėta, kad kartais,
funkcijai perdavus taip, ji netikėtai gražina false. Tada funkcija buvo papildyta pora patikros
eilučių: function arTaip(eil) { alert(eil); alert(eil === "taip"); return eil === "taip"; } Ir tada vieno kreipinio metu funkcija gražino taip ir false! Kas čia vyksta! Priežastis - operatoriaus === veikime. Parašykime tokį testavimo kodą mūsų funkcijai: var E1 = "taip"; arTaip(E1); var E2 = new String("taip"); arTaip(E2); Pirmosios eilutės atveju gausime atsakymą true, o antrosios - false. Mat === tikrina
tapatumą, kuris yra daugiau, nei vien reikšmė. Abu argumentai turi būti nuorodos į tą patį objektą. E2 yra
kitas eilutės tipo objektas nei "taip" objektas. Įsitikinimui, papildykime mūsų testinį kodą tokiomis
eilutėmis: Atsakymas bus, kad E2 ir E3 yra nelygūs! Tačiau padėtis pasitaiso, jei bus panaudotas priskyrimo
operatorius: nes šįkart patenkinama tapatybės patikra. Dar įdomiau, kad false gausime ir naudodami ==
operatorių (kai tikimės tik reikšmių sutapimo palyginimo) su skirtingų objektų kintamaisiais. Tuo tikslu
išbandykime naują testinį pavyzdį: var E2 = new String("taip"); var E3 = new String("taip"); alert (E2 == E3); Čia problema tame, kad JavaScript neturi aiškaus reikšmės tipo, į kurį automatiškai konvertuotų
eilutės tipą (kitaip sakant, nemoka String tipo objekto versti į primityvųjį eilutės tipą). Ir jei jau manote, kad
viskas toliau aišku, tai mažas testas jums nuspėkite (mintyse) šio (žemiau) fragmento rezultatus! var E2 = new String("taip"); var E3 = new String("taip"); alert (E2.toString() === E3); alert (E2.toString() == E3); Na? O dabar patikrinkite su kompiuteriu... Atspėjote?! Pirmu atveju yra false, o antru true. Ir čia galite vietoje toString() panaudoti bet kurį kitą eilutės metodą, pvz., toLowerCase rezultatas bus tas pats (false ir true). Taip yra todėl, kad visi eilutės tipo metodai gražina primityvųjį reikšmės tipą, o ne String tipo objektą. Ir nesvarbu, ką rašo vadovėliuose, eilutės konstanta yra objektas kito tipo, nei String. Jei eilutės konstanta panaudojama tarsi ji būtų String objektas, ji, prieš panaudojimą, automatiškai konvertuojama į String tipo objektą. Todėl programose galime naudoti eilučių konstantas tarsi jos būti String tipo tačiau taip nėra! Ir galutinai sumaištį sukelia faktas, kas jei String objektą sukursime nenaudodami konstruktoriaus (t.y.,
be new), gausime primityvųjį eilutės tipą (t.y., eilutės konstantą). Tad toks pavyzdys grąžins true
(taigi new panaudojimas iššaukia didelį skirtumą):
Hm, ar tikrai galvojote, kad tiek niuansų gali būti lyginant dvi teksto eilutes? Ir nelengva duoti patikimą
patarimą, šio tipo problemų išvengimui. Pirma, jei viena iš lyginamų eilučių yra konstanta, saugiau naudoti
== (nepaisant rekomendacijų). Jei nesate tuo tikri, tada problema gerokai sudėtingesnė, ir geriausias
apsidraudimas būtų naudoti taip: Ir tai nėra klaida JavaScipt realizacijoje tokia problema yra bendra visoms kalboms su silpna tipų kontrole bei dinaminiais objektais. Kai į žaidimą įtraukiamas automatinis objektų reikšmių konvertavimas, iškart kyla potencialus pavojus. Ankstesnės "Advanced HTML" skyrelio temos:
| |