Kirjoittaja: MikaBug (2007).
⚠ Huomio! Tämä opas on vanhentunut. Oppaan sisältöön ei voi enää luottaa. Opas on säilytetty vain sen historiallisen arvon vuoksi. ⚠
Tämä opas kertoo perusteet olio-ohjelmoinnista JavaScriptissä. Olio-ohjelmointi on niin laaja käsite, että sen tarkka läpikäyminen vaatisi oman paksun opaskirjansa ja taitavamman kirjoittajan. Tässä oppaassa kerrotaan kuitenkin pohjatiedot omien olioiden ja metodien luomisesta ja niihin viittamisesta.
JavaScript on oliopohjainen kieli. Esimerkiksi paljon käytetty document.write
koostuu oliosta document
ja sen metodista write
. Metodi on siis toiminto, jonka olio pystyy toteuttamaan. Metodi on sama asia kuin funktio, mutta jos funktio on osana oliota, kutsutaan sitä metodiksi.
Käytännössä olio on jonkin asian yleinen käsite, esimerkiksi Auto voisi olla olio. Autoja on kuitenkin monen merkkisiä, värisiä, kokoisia ja hintaisia. Nämä erilaiset autot ovat Auto-olion ilmentymiä. Niillä on siis samat ominaisuudet, mutta eri arvot (esimerkiksi kolmella autolla on kaikilla väri, mutta yksi voi olla vihreä, toinen punainen ja kolmas musta).
Olio sisältää siis erilaisia ominaisuuksia (attribuutteja), jotka ohjelmoinnissa tallennetaan muuttujiin. Autojen tapauksessa ominaisuuksia ovat muun muassa merkki, malli, väri ja hinta. Henkilötietoja kysyvässä ohjelmassa voisi olla Henkilo-olio, jonka ominaisuuksia olisivat etunimi, sukunimi, syntymäaika jne.
Ominaisuuksien lisäksi olio sisältää yleensä metodeita, joilla käsitellään olion sisältämiä tietoja, eli muuttujien arvoja. Esimerkiksi Henkilo-oliossa voisi olla NaytaTiedot-metodi, joka tulostaa näyttöön henkilön tiedot, tai MuokkaaTietoja-metodi, jonka avulla tietoja pääsee muuttamaan.
Ensiksi luodaan yksinkertainen olio, jolla ei ole yhtään metodia. Olio määritellään kuten funktiokin function
-komennolla. Olion nimen perässä oleviin sulkuihin tulevat olion parametrien nimet. Varsinainen sisältö tulee aaltosulkujen { }
sisälle. this
-osoittimella tiedot saadaan koskemaan oliota itseään.
function Henkilo(etunimi, sukunimi, ika) { // Sijoitetaan parametreina tulevat tiedot olion omiin muuttujiin: this.etunimi = etunimi; this.sukunimi = sukunimi; this.ika = ika; }
Sitten voidaan luoda pari ilmentymää oliolle new
-operaattorilla. Oliolle viedään parametreina henkilön tiedot eli etunimi, sukunimi ja ikä.
var Heikki = new Henkilo("Heikki", "Huttunen", 34); var Saija = new Henkilo("Saija", "Sopanen", 18);
Nyt meillä on kaksi Henkilo
-nimisen olion ilmentymää, Heikki ja Saija, jotka molemmat sisältävät omat tietonsa. Tietoihin pääsee käsiksi syntaksilla olio.ominaisuus
.
document.write(Heikki.etunimi); // Tulostaa "Heikki" document.write(Saija.sukunimi); // Tulostaa "Sopanen"
Samalla tavalla String-tyyppisen merkkijonon pituus saatiin selville length
-ominaisuudella:
var merkkijono = "Tekstiä"; document.write(merkkijono.length); // Tulostaa 7
Vaihtoehtoisesti olion tietoihin voidaan osoittaa indeksin avulla tyyliin Saija["sukunimi"]
. Jos haluamme muuttaa Heikin sukunimeksi Virtanen, tapahtuu se seuraavalla tavalla:
Heikki.sukunimi = "Virtanen"; // tai Heikki["sukunimi"] = "Virtanen";
Lisätään olioon metodi NaytaTiedot
, joka tulostaa selaimeen henkilön etu- ja sukunimen sekä iän. Metodi määritellään vastaavalla tavalla kuin funktio. Metodissa viitataan olion muuttujiin this
-osoittimen avulla var etunimi = this.etunimi;
. Eli metodin etunimi
-muuttujaan sijoitetaan arvo olion etunimi
-muuttujasta.
function NaytaTiedot() { // Sijoitetaan olion muuttujien sisältö metodin muuttujiin: var etunimi = this.etunimi; var sukunimi = this.sukunimi; var ika = this.ika; document.write("Henkilön nimi on " + etunimi + " " + sukunimi + " ja hän on " + ika + "-vuotta vanha."); }
Metodia ei siis kirjoiteta suoraan olion määrittelyyn aaltosulkujen { }
sisäpuolelle, vaan omaksi erilliseksi funktioksi. Metodi yhdistetään olioon kirjoittamalla olion määrittelyyn lauseke this.tiedot = NaytaTiedot;
. Huomaa, että metodin nimi tulee ilman sulkuja. Metodiin viitataan syntaksilla olio.metodi()
, eli esimerkiksi Saija.tiedot()
, joka tulostaa näyttöön Saijan tiedot. Kokonaisuutena koodi näyttää tältä:
<script type="text/javascript"> // Luodaan olio Henkilo: function Henkilo(etunimi, sukunimi, ika) { // Sijoitetaan parametreina saatavat tiedot olion omiin muuttujiin: this.etunimi = etunimi; this.sukunimi = sukunimi; this.ika = ika; // Liitetään metodi olioon: this.tiedot = NaytaTiedot; } // Luodaan Henkilo-oliolle metodi NaytaTiedot: function NaytaTiedot() { // Sijoitetaan olion muuttujien sisältö metodin muuttujiin: var etunimi = this.etunimi; var sukunimi = this.sukunimi; var ika = this.ika; document.write("Henkilön nimi on " + etunimi + " " + sukunimi + " ja hän on " + ika + "-vuotta vanha."); } // Luodaan kolme ilmentymää oliolle Henkilo: var Hannu = new Henkilo("Hannu", "Repo", 70); var Heikki = new Henkilo("Heikki", "Huttunen", 34); var Saija = new Henkilo("Saija", "Sopanen", 18); // Tulostetaan Hannun tiedot: Hannu.tiedot(); // Tulostetaan Saijan tiedot: Saija.tiedot(); </script>
Edellisessä esimerkissä metodille ei viety yhtään parametria. Metodille on kuitenkin mahdollista viedä parametreja sitä kutsuttaessa. Kutsu on silloin muotoa olio.metodi(param_1, param_2,...,param_n)
. Kehitetään edellistä skriptiä siten, että henkilöiden tietoja voidaan muuttaa MuutaTiedot
-metodin kautta. Aloitetaan määrittelemällä uusi metodi.
function MuutaTiedot(etunimi, sukunimi, ika) { this.etunimi = etunimi; this.sukunimi = sukunimi; this.ika = ika; }
Metodin määrittelyn pitäisi näyttää tutulta lukuun ottamatta metodille vietäviä parametreja, jotka on kirjoitettu metodin nimen perässä olevien sulkujen sisään pilkuin erotettuna. Metodissa parametrin sisältämä arvo sijoitetaan olion vastaavaan muuttujaan. Parametrin nimen ei tarvitse välttämättä olla sama kuin olion muuttujan nimi. Seuraava metodi toimii aivan yhtä hyvin:
function MuutaTiedot(enimi, snimi, ika) { this.etunimi = enimi; this.sukunimi = snimi; this.ika = ika; }
Toisin sanoen kutsun yhteydessä annettavat parametrit sijoitetaan olion muuttujien arvoiksi. Uusi metodi MuutaTiedot
liitetään olion määrittelyyn lauseella this.muuta = MuutaTiedot;
. Näin metodiin viitataan esimerkiksi lauseella Seija.muuta(param_1, param_2, param_3);
.
Alla aiempi skripti, johon on lisätty mahdollisuus muuttaa henkilön tietoja.
<script type="text/javascript"> // Luodaan olio Henkilo: function Henkilo(etunimi, sukunimi, ika) { // Sijoitetaan parametreina saatavat tiedot olion omiin muuttujiin: this.etunimi = etunimi; this.sukunimi = sukunimi; this.ika = ika; // Liitetään metodit olioon: this.tiedot = NaytaTiedot; this.muuta = MuutaTiedot; } // Luodaan Henkilo-oliolle metodi NaytaTiedot: function NaytaTiedot() { // Sijoitetaan olion muuttujien sisältö metodin muuttujiin: var etunimi = this.etunimi; var sukunimi = this.sukunimi; var ika = this.ika; document.write("Henkilön nimi on " + etunimi + " " + sukunimi + " ja hän on " + ika + "-vuotta vanha."); } // Luodaan Henkilo-oliolle metodi MuutaTiedot: function MuutaTiedot(enimi, snimi, ika) { this.etunimi = enimi; this.sukunimi = snimi; this.ika = ika; } // Luodaan kolme ilmentymää oliolle Henkilo: var Hannu = new Henkilo("Hannu", "Repo", 70); var Heikki = new Henkilo("Heikki", "Huttunen", 34); var Saija = new Henkilo("Saija", "Sopanen", 18); // Tulostetaan Hannun tiedot: Hannu.tiedot(); // Tulostetaan Saijan tiedot: Saija.tiedot(); // Muutetaan Saijan tietoja: Saija.muuta("Mervi", "Pasanen", 71); // Tulostetaan tiedot muutoksen jälkeen: Saija.tiedot(); </script>
Metodi pystyy funktion tavoin palauttamaan yhden arvon return
-lauseella. Toiminta on hyvin samankaltainen kuin funktioiden tapauksessa.
<script type="text/javascript"> function Henkilo(etunimi, sukunimi, ika) { this.etunimi = etunimi; this.sukunimi = sukunimi; this.ika = ika; this.syntymavuosi = Syntymavuosi; } function Syntymavuosi(tama_vuosi) { // Syntymäaika lasketaan vähentämällä kuluvasta vuodesta ikä: var syntymavuosi = tama_vuosi - this.ika; // Metodi palauttaa syntymavuosi-muuttujan arvon: return syntymavuosi; } var Matti = new Henkilo("Matti", "Muukalainen", 24); // Metodille viedään parametrina kuluva vuosi: var syntymavuosi = Matti.syntymavuosi(2007); document.write(syntymavuosi); </script>
Jos luomme vaikkapa viisi Henkilo-olion ilmentymää, voimme tallentaa ne taulukkoon, jolloin niihin viittaaminen tapahtuu indeksien avulla. Näin eri henkilöiden tiedot on helppo käydä läpi esimerkiksi for-silmukalla. Seuraavassa skriptissä luodaan viisi Henkilo-olion ilmentymää, sijoitetaan niihin henkilöiden tiedot ja tulostetaan ne for-silmukalla selaimeen.
<script type="text/javascript"> // Luodaan olio Henkilo: function Henkilo(etunimi, sukunimi, ika) { // Sijoitetaan parametreina saatavat tiedot olion omiin muuttujiin: this.etunimi = etunimi; this.sukunimi = sukunimi; this.ika = ika; // Liitetään metodi olioon: this.tiedot = NaytaTiedot; } // Luodaan Henkilo-oliolle metodi NaytaTiedot: function NaytaTiedot() { // Sijoitetaan olion muuttujien sisältö metodin muuttujiin: var etunimi = this.etunimi; var sukunimi = this.sukunimi; var ika = this.ika; document.write("Henkilön nimi on " + etunimi + " " + sukunimi + " ja hän on " + ika + "-vuotta vanha.<br>"); } // Luodaan henkilot-taulukko viiden henkilon tiedoille: var henkilot = new Array(5); // Jokaiseen taulukon soluun luodaan Henkilo-olion ilmentymä ja viedään sille parametrina henkilön tiedot: henkilot[0] = new Henkilo("Hannu", "Repo", 70); henkilot[1] = new Henkilo("Saija", "Sopanen", 18); henkilot[2] = new Henkilo("Ismo", "Ratinen", 41); henkilot[3] = new Henkilo("Riitta", "Rahkonen", 28); henkilot[4] = new Henkilo("Heikki", "Huttunen", 34); // Silmukkaa kierretään, kunnes kaikki henkilöt on käyty läpi: for(var j = 0; j < henkilot.length; j++) { henkilot[j].tiedot(); } </script>
Koska taulukoiden koko pystyy kasvamaan automaattisesti (dynaamisesti), voidaan henkilot
-taulukkoon lisätä uusia Henkilo
-olion ilmentymiä uusilla tiedoilla tarvittava määrä. Kuudes henkilö lisättäisiin lauseella henkilot[5] = new Henkilo("Pertti", "Partanen", 14);
. for-silmukka osaa käydä kaikki henkilöt läpi, koska taulukon koko (solujen määrä) selvitetään lauseella henkilot.length
. Tällöin silmukka mukautuu kasvavaan taulukkoon automaattisesti.
Tässä oppaassa oli vasta melko pintapuolinen raapaisu olio-ohjelmointiin. Sinulla pitäisi kuitenkin olla nyt käsitys, mitä olio-ohjelmointi on, kuinka omia olioita luodaan ja miten niihin viitataan. Olioiden käyttö selkeyttää koodia, tekee siitä helpommin ylläpidettävän ja mahdollistaa ohjelman osien eli olioiden uudelleenkäytön muissa skripteissä, joten olio-ohjelmointiin kannattaa perehtyä.
Seuraava opas on sarjan viimeinen, ja siinä käydään läpi käytännön esimerkkien kautta muun muassa kellonajan ja päivämäärän käsittely, ajastimen käyttö pienimuotoisessa animaatiossa sekä hiireen reagoivien painikkeiden ohjelmointi.
Olisi ollut myös hyvä mainita tapa luoda objekteja käyttämällä assosiatiivisia taulukoita, jotka itseasiassa JavaScriptissä ovat tyyppiä "object", eli objekti.
Esim:
Markku = { ika: 42, pituus: "182cm", paino: "80kg", kerroTiedot: function() { document.write("Markku on " + this.ika + " vuotta vanha, on " + this.pituus + " pitkä ja painaa " + this.paino + "."); } }
Luokan metodit voi kyllä laittaa sen luokan sisäänkin:
function MyClass(){ this.getString = getString; function getString(){ return "mwahahahhaha"; } }
Matson esimerkissä jokainen kloonattu olio saa oman kopion funktiosta getString
. Yleensä tähän ei ole tarvetta, ja on tehokkaampaa käyttää prototyyppiä:
function MyObject() { // ... } MyObject.prototype.getString = function () { return "String"; };
Hassua ettei prototyypeistä puhuta oppaassa mitään, vaikka niiden ymmärtäminen on ehdottoman tärkeää jos haluaa oppia JavaScriptin hyvin.
Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.