Kurssin tavoitteena on ollut JavaScriptin sisäisen toiminnan ymmärtäminen, kielen "pelimoottorin" logiikan hahmottaminen. JavaScript-ohjelman suoritusaikainen dynaamisuus – kaikkea voi vauhdissa muuttaa – on johtanut siihen, että on mahdollista kehittää hyvin erilaisia ohjelmointityylejä ja -tapoja. Ja onhan niitä kehiteltykin!
JavaScript-ohjelman suoritus kuitenkin aina lopulta palautuu dynaamisesti muokattavaan assosiaatiolistojen verkkoon. Erilaisten ohjelmointityylien ja -tekniikoiden ymmärtämisen edellytys on tuon verkon rakenteen ymmärtäminen. Siihen perustuen on mahdoillista kehitellä myös kokonaan uusia tyylejä ja ehkäpä vieläkin parempia rakenneratkaisuja.
Tässä luvussa kurkistellaan esimerkinomaisesti joihinkin verkosta löytyviin JavaScript-ohjelmoinnin rakennehahmoihin suunnittelumalleihin ("design pattern").
function Otus(nimi) { // Tämä on se tuttu ja tapa!
this.nimi=nimi
this.laji="kissa"
}
Otus.prototype.kuka= function() {write(this.nimi+" "+this.laji)}
var x = new Otus("Missu")
x.kuka() // Missu kissa
var y = new Otus("Murre")
y.kuka() // Murre kissa
y.laji = "koira"
y.kuka() // Murre koira
y.kuka = function() {write("Hau, hau!")}
y.kuka() // Hau, hau!
x.kuka() // Missu kissa
function Otus(nimi) {
this.nimi=nimi
this.laji="kissa"
// yksityinen kenttä ja yksityinen funktio:
var lkm=3
function viela() {lkm -= 1; return lkm>=0}
// talletetaan luontihetken this yksityiseen kenttään that:
var that = this
// jukinen funktio:
this.kuka = function()
{if (viela())
write(that.nimi+" "+that.laji)
else
write("Kaikki "+that.nimi+"-kysymykset käytetty!")
}
}
var x = new Otus("Missu")
var y = new Otus("Murre")
y.laji = "koira"
x.kuka() // Missu kissa
x.kuka() // Missu kissa
x.kuka() // Missu kissa
y.kuka() // Murre koira
x.kuka() // Kaikki Missu-kysymykset käytetty!
y.kuka() // Murre koira
x.kuka() // Kaikki Missu-kysymykset käytetty!
y.kuka() // Murre koira
y.kuka() // Kaikki Murre-kysymykset käytetty!
function Olio(nimi) {
this.nimi=nimi
}
Olio.prototype.postilaatikko=0
Olio.prototype.postita=function(a) {Olio.prototype.postilaatikko=a}
var x = new Olio("abc")
var y = new Olio("def")
x.postita("Moi! Mitä kuuluu?")
write(y.postilaatikko) // Moi! Mitä kuuluu?
y.postita("Kiitos hyvää.")
write(x.postilaatikko) // Kiitos hyvää.
x.postilaatikko = "EVVK!" write(y.postilaatikko) // Kiitos hyvää.
var laskuri = (function () {
var counter = 0; // sulkeuman yksityinen muuttuja
// funktio palauttaa arvonaan olion, jossa on kaksi aksessoria,
// jotka käsittelevät sulkeumaan suljettua vapaata muuttujaa:
return {
incrementCounter: function () {
return counter++;
},
resetCounter: function () {
write( "Laskurin arvo ennen nollausta: " + counter );
counter = 0;
}
};
})(); // HUOM: Funktio siis suoritetaan saman tien!
write(laskuri.incrementCounter()) // 0
write(laskuri.incrementCounter()) // 1
write(laskuri.incrementCounter()) // 2
laskuri.resetCounter(); // Laskurin arvo ennen nollausta: 3
write(laskuri.incrementCounter()) // 0
write(laskuri.incrementCounter()) // 1
laskuri.incrementCounter = () => 666 write(laskuri.incrementCounter()) // 666 write(laskuri.incrementCounter()) // 666 write(laskuri.incrementCounter()) // 666 ...
function Olio(nimi) {
this.nimi=nimi
}
Olio.prototype.posti =
(function () {
var postilaatikko=0
return {
laheta: function(a) {postilaatikko=a},
lue: function() {return postilaatikko}
}
})()
var x = new Olio("abc")
var y = new Olio("def")
x.posti.laheta("Moi! Mitä kuuluu?")
write(y.posti.lue()) // Moi! Mitä kuuluu?
y.posti.laheta("Kiitos hyvää.")
write(x.posti.lue()) // Kiitos hyvää.
x.posti.laheta("EVVK!")
write(y.posti.lue()) // EVVK!
y.posti.laheta(123)
write(x.posti.lue()) // 123
function teeUusiLaskuri() {
var counter = 0; // sulkeuman yksityinen muuttuja
// funktio palauttaa arvonaan olion, jossa on kaksi funktiota,
// jotka käsittelevät sulkeuman yhteistä muuttujaa:
return {
incrementCounter: function () {
return counter++;
},
resetCounter: function () {
write( "Laskurin arvo ennen nollausta: " + counter );
counter = 0;
}
};
} // HUOM: Funktiota ei suoriteta vielä!
var x = teeUusiLaskuri()
write(x.incrementCounter()) // 0
write(x.incrementCounter()) // 1
write(x.incrementCounter()) // 2
x.resetCounter(); // Laskurin arvo ennen nollausta: 3
var y = teeUusiLaskuri()
write(y.incrementCounter()) // 0
write(y.incrementCounter()) // 1
write(y.incrementCounter()) // 2
write(y.incrementCounter()) // 3
write(y.incrementCounter()) // 4
y.resetCounter(); // Laskurin arvo ennen nollausta: 5
write(x.incrementCounter()) // 0
write(x.incrementCounter()) // 1
(function () {
// - muuttujien ja funktioiden määrittelyitä
// - täältä näkee ulos, mutta ulkoa ei näy tänne
// - tänne voidaan sulkea ympäristön vapaita muuttujia
}());
var MODULE = (function () {
// privaattiosuus:
var privaatti = 1
function privaattimetodi() {
// ...
}
var my = {} // tähän rakennetaan julkinen rajapinta
// julkinen rajapinta:
my.julkinen = 456;
my.privaatinArvo = function() {return privaatti}
my.kasvataPrivaattia = function (x) {privaatti += x}
return my;
}());
write(MODULE.julkinen) // 456
write(MODULE.privaatinArvo()) // 1
MODULE.kasvataPrivaattia(22)
write(MODULE.privaatinArvo()) // 23
Sivu Brainfuck beware: JavaScript is after you! kertoo, miten se käy. En todellakaan aio perehtyä yksityiskohtiin... ;-)