JavaScript
JavaScript on ohjelmointikieli jota käytetään erityisesti WWW-sivujen yhteydessä.Row 71: TypeError: saatilat isnot iterable Interaktiivisesti voi pelata vain kahta ensmmäistä console.log ja sitten error stoppaa tulosteen
—Vika on korjattu
—Tuloksiin tulee edelleen ain kaksi ensimmäistä console.log() tulosta.
—malli.js on edelleen muuttamatta, samalla lilla kuin vieressä on muutettu koodia.
—Onko tämä siis se mistä puhuttiin tunnilla, joka kysyy avaimet? for (let paikka of Object.keys(saatilat)) { console.log( paikka + " : " + saatilat[paikka] ); }
—Luennolla tehty esimerkki: malli.html ja malli.js
1. ECMAscript
JavaScript on alunperin kehitetty Netscape-selaimeen 1990-luvulla. JavaScript-kieli on nykyään standardoitu ECMAScript-standardissa. ECMAScript-kieltä kehitetään edelleen. Tällä hetkellä uusin versio on ECMAScript 2019 mutta käytännössä käytössä on ECMAScript 2015 (ES6).
Voit kirjoittaa JavaScriptia uusimmalla kielen versiolla ja kääntää Babelin avulla vanhempaan versioon.
JavaScript (ECMAScript) -kieltä käytetään useissa eri yhteyksissä, mutta erityisesti WWW-selaimissa. Selaimessa suoritetulla JavaScriptilla voi muokata selainympäristöä ja siihen liittyviä objekteja.
- JavaScript ei liity millään tavalla Java-ohjelmointikieleen
- JavaScriptissä käytetään dynaamista tyypitystä. Jos haluat staattisen tyypityksen niin ks. TypeScript
- JavaScript on prototyyppipohjainen kieli eikä luokkapohjainen kuten esim. Java
vahva tyypitys = tyyppi pysyy, heikko/olematon tyypitys = tyyppi muuttuu staattinen tyypitys = tyyppi kirjoitetaan lähdekoodiin, dynaaminen tyypitys = tyyppi päätellään arvosta
Tuossakin on vähän epäselvyyksiä, mutta myöhemmät kurssit selvittävät asian. -ji
—2. Visual Studio Code ja JSHint
Hyvä editori Javascriptin kirjoittamiseen on Visual Studio Code. Huom. tämä on eri asia kuin Visual Studio.
Visual Studio Coden liveserver-ominaisuudesta voi olla paljon apua.
On myös muita vaihtoehtoja. Visua Studio Code on varsin iso ja raskas ohjelma. Moniin pikkukokeiluihin riittää selaimen sisältämät kehitystyökalut.
—JSHint on työkalu, joka automaattisesti tarkistaa javascript-koodin laatua ja virheitä. JSHintin voi asentaa laajennoksena Visual Studio codeen.
Valitettavasti tämä ei vielä riitä vaan varsinainen JSHint pitää asentaa npm:n avulla joko omalle koneelle tai lokaalisti siihen kansioon, joka on Visual Studio Codessa avoinna. Npm on asennustyökalu, joka tulee nodejs:n mukana. Nodejs on ympäristö, jolla voi suorittaa javascriptia muuallakin kuin selaimessa. Node.js ei liity tämän kurssin aiheisiin, joten emme mene sen käyttämiseen tarkemmin. Yliopiston mikroilla ei nodea ole asennettuna, joten JSHintin asentaminen on hieman hankalaa. Jalava- ja Halava-palvelimista node ja npm löytyvät, mutta ne ovat hieman vanhat versiot.
Seuraavassa paketissa pitäisi olla valmiina kaikki JSHintin tarvitsemat kirjastot.
http://appro.mit.jyu.fi/tiea2120/jshint.zip
Purkakaa paketti Visual Studio Codessa avoinna olevan kansiorakenteen juureen. Asentakaa Visual Studio Codeen JSHint-laajennus. Jos kaikki toimii niin Problems-ikkunaan ilmestyy JSHintin ilmoituksia. Paketin mukana on myös .jshintrc-tiedosto, johon on määritelty sopivat säädöt JSHintin tarkistuksille. Niitä voi tarpeen mukaan itse muutella. JSHintin Asetuksia voi määritellä myös Visual Studio Coden settingsien kautta.
3. JavaScript-ohjelman suorittaminen
JavaScript-ohjelmat suoritetaan yleensä selainympäristössä. Tämä tarkoittaa JavaScript-sovelluksen linkittämistä WWW-sivun yhteyteen. JavaScript-ohjelma pääsee käsiksi kyseisen WWW-sivun sisältöön ja sen ulkoasuun.
JavaScript liitetään www-sivuun script
-elementillä yleensä head-osassa:
<script type="text/javascript" src="jokutiedosto.js"></script>
Mallipohja:
<!DOCTYPE html> <html lang="fi"> <head> <meta charset="UTF-8" /> <title>Mallipohja</title> <script type="text/javascript" src="malli.js"></script> </head> <body> </body> </html>
JavaScriptiä voi harjoitella myös suoraan selaimessa konsolin tai konsolin avulla tai JSFiddle- ja jsbin-palveluissa.
console.log-funktiolla voit tulostaa tietoja suoraan selaimen konsoliin.
console.log("testi");
How you can improve your workflow using the JavaScript console
Luennolla näytetty malli2020.html ja malli2020.js.
4. Työvälineet
- Visual Studio Code
- Firefox- ja Brave- ja Chrome-www-selaimet
- MacOS:ssä Safari on mainio selain käytettäväksi tähänkin. Firefoxissa toki on hieman edistyneempi JavaScript-debuggeri.
- Jos se ärsyttää, että Visual Studio soittaa kotiin Micro$oftille, voit toki kääntää sen itse tai käyttää VSCodiumia.
- Atom, Emacs, Sublime ja Vim toimivat myös erittäin hyvin JavaScript-koodaukseen.
5. Syntaksi
JavaScriptin syntaksista kannattaa lukea seuraavia lähteitä:
- A re-introduction to JavaScript
- Introduction to JavaScript
- JavaScript - Mozilla Developer Center
- Eloquent JavaScript
Suositeltavaa on suorittaa ohjelma Strict modessa. Kirjoita ohjelmakoodisi alkuun rivi:
"use strict";
Lisää myös seuraava rivi, jos haluat visual studio coden ajavan TypeScriptin tyyppitarkistuksen ohjelmakoodillesi. Koodisi ei tarvitse olla TypeScriptiä. Mahdolliset ongelmat näet Visual Studio Coden problems-ikkunassa View|Problems (Ctrl+Shift+M) Saatat saada myös jotain turhia virheilmoituksia.
//@ts-check
5.1 Ympäristö
JavaScriptiä suoritetaan määrätyssä ympäristössä, joka voi olla esimerkiksi selaimessa. JavaScript ei itsessään määrittele, miten tietoa voidaan syöttää tai tulostaa, vaan se tarjoaa ainoastaan tiedon käsittelymekanismit. Tiedon syöttö ja vasteiden anto tehdään käyttäen HTML:ää ja Document Object Model (DOM) -rajapintaa.
5.2 Yleistä
- Isoilla ja pienillä kirjaimille on merkitystä (Foo on eri kuin foo)
- Merkistönä käytetään Unicodea
- Lauseet päättyvät puolipisteeseen (;). Javascript ei kuitenkaan kaikissa tilanteissa kaipaa puolipistettä (;) lauseen loppuun. On erittäin suositeltavaa käyttää puolipistettä aina, paitsi lohkon jälkeen.
- Kommentit merkitään kuten C++:ssa: // ja /* */
5.3 Muuttujat ja arvot
JavaScript on dynaamisesti tyypitetty kieli. Muuttujien tyyppi määräytyy siis arvon perusteella. Jokaisen arvon tyyppi kuitenkin on pysyvä ja selvitettävissä, joten kyse ei ole heikosti tyypitetystä tai tyypittömästä kielestä.
Voit halutessasi käyttää TypeScript-kieltä, joka lisää JavaScriptiin käännösaikaisen tyypintarkastuksen. TypeScript-koodi käännetään tavalliseksi JavaScriptiksi.
JavaScriptissä muuttujat tulee esitellä ennen käyttöä. Tämä tapahtuu avainsanalla let
tai var
seuraavasti:
TODO: TypeScript-kommentti on ihan väärässä paikassa.
—Yllä olevien rivien suorituksen jälkeen a
:n arvo on 0
ja b
:n arvo on undefined
, eli määrittelemätön. Avainsanalla let
esitellyt muuttujat tulee alustaa ennen käyttöä, joten ne eivät koskaan voi olla arovoltaan undefined
.
Avainsana var
oli yleinen ennen kuin let
lisättiin kieleen. var
kuitenkin sisälsi monia sudenkuoppia, joten nykyään on parempi opetella heti aluksi käyttämään let
-avainsanaa. Lyhyesti näillä on erona edellä esitellyn lisäksi se, että let
-avainsanalla esitellyt muuttujat ovat käytettävissä vain esittelylohkonsa sisällä, kun taas var
-avainsanalla esitellyt valuvat lohkon ulkopuolelle. Lohko on karkeasti määriteltynä {}
-sulkuparin välinen alue. var
-avainsanalla määritellyn muuttujan näkyvyysalueen rajaa kuitenkin se funktio, jossa sitä on käytetty, joten ei var
globaaleja muuttujia luo. Sillekin on vielä käyttönsä. Tarkemmin asiasta voi lukea vaikkapa Mozillan kehittäjäsivuilta tai getifyn kirjoituksesta Githubissa.
Eli käytä tästä eteenpäin avainsanaa let
, ja vain jos on pakko tai käyttämäsi selain ei sitä tue, käytä var
.
Monissa kielissä let
esittelee kertaalleen sijoitettavan muuttujan, jonka arvoa ei voi muuttaa. Jos tarvitset tällaisen JavaScriptissä, käytä muuttujan esittelyyn avainsanaa const
.
Muuttujien tyyppiä ei tarvitse esitellä, sillä kuten parametrit, ne ovat viitteitä arvo-olioihin. Korostetaan tässä vielä, että arvon tyyppi ei voi JavaScriptissä muuttua, vaikka arvo voidaan implisiittisesti muuttaa toiseksi tarvittaessa.
5.3 Tietotyypit
- Boolean
- null
- undefined
- Number
- String
- Symbol
- Object
Javascript muuntaa automaattisesti muuttujan tyyppiä tilanteen mukaan.
Eikä muuta! JavaScriptissä käytetään viitteitä. Lisäysfunktio + tuottaa erilaisia olioita sen mukaan, mitä sen parametrit ovat. Siksi sitä ei kannata käyttää holtittomasti! -ji
—Ensimmäisessä tapauksessa rivillä 2 on yhteenlaskun tulos merkkijono, sillä numero muutetaan ensin merkkijonoksi ja tämän jälkeen liitetään ensimmäiseen merkkijonoon.
Jos hampaita kiristää ja silmiä siristää, liitostamisen voinee tulkita yhteenlaskuksi, mutta silti... ei! Tarjolla on toki parempi metodikin:
"wat".concat(1);
Tuo on juuri se, mitä tuossa muka-yhteenlaskussa tehdään.
Toisessa tapauksessa rivillä 6 vuorostaan on tyystin outo yritys vähentää jotain merkkijonosta. Sitä saa mitä tilaa: NaN
tarkoittaa ”not a number”.
Muuttujat esitellään seuraavasti:
Muuttujien nimeämissäännöt ovat kuten Javassa.
Jos muutat String-arvon Number-arvoksi niin tee se parseInt- tai parseFloat-funktiolla.
kts. myös isInteger
Huomioi seuraavaa:
-
Liukulukujen tarkkuus n.15 desimaalia.
0.2 + 0.1111 = 0.31110000000000004
Tulos on pyöristettävä sopivaan tarkkuuteen. -
Muuttujalla voi olla myös muutama erikoisarvo:
-
NaN - Not-A-Number
isNaN(NaN); // true Nan === NaN // false!
- Infinity ja -Infinity - äärettömyydet
- null - viittaus tyhjään. null on objekti
-
undefined - arvoa ei määritelty. Ei ole sama asia kuin null. undefined ei ole objekti.
if ( typeof x === 'undefined')
if ( x === undefined)
- Three common mistakes in JavaScript
- Numeric literals
-
NaN - Not-A-Number
5.2.1 Lohkot
Muuttujan näkyvyys rajoittuu funktion sisälle, jos muuttuja esitellään var-etuliitteellä. Ennen ECMAScript 2015:sta ja let-muuttujanesittelyä Javascriptissa EI ole ollut lohkon sisäisiä muuttujia
function foobar() { var p = 1; // tämä muuttuja on voimassa vain tässä funktiossa { var p = 2; // Tällä on sama näkyvyysalue kuin edellisellä } console.log(p); // tulostaa 2 }
5.3 Operaattorit
- ks Guide
Käytössä on normaalit aritmeettiset ja vertailuoperaattorit. Vrt. Java
-
Vaikka 0, tyhjä merkkijono, NaN, null ja undefined ovat loogisissa operaatioissa totuusarvoltaan false, kaikki muut true, kannattaa käyttää avainsana-arvoja
true
jafalse
aina kun mahdollista. - !! antaa muuttujan totuusarvon
- Matemaattisia operaatioita varten on olemassa globaali objekti Math
-
=== tarkistaa ovatko saman arvoiset ja samaa tyyppiä. Käytä tätä jos yrität tutkia onko jokin null tai undefined. === ja !== operaattorit eivät muunna vertailtavana olevia objekteja mitenkään. Tavallinen == yrittää muuntaa objektit samantyyppisiksi.
1 === "1" // epätosi 1 == "1" // tosi
Vertailuissa on oltava tarkkana, sillä (löyhä) yhtäsuuruusoperaattori ==
pyrkii tekemään liikaa implisiittisiä oletuksia. On helpompi käyttää (tiukkoja) operaattoreita ===
ja !==
sekä olioiden vertailumetodeja noiden enemmän arvaavien (löyhien) operaattorien (==
ja !=
) sijaan. EcmaScript 6 tuo tarjolle myös metodin Object.is(tämä, tuo)
, joka vastaa tiukkaa yhtäsuuruutta muille paitsi numeroille +0
, -0
vertailtaessa arvoon NaN
. (Ks. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness)
delete-operaattori poistaa objektin, ominaisuuden tai elementin taulukosta.
typeof-operaattori palauttaa merkkijonon, joka kertoo kohteena olleen objektin tyypin.
in-operaattori palauttaa true jos kysytty ominaisuus löytyy kohteena olevasta objektista.
instanceof-operaattorilla voi testata objektin tyypin
new-operaattorilla voi luoda uusia objekteja
5.4 Merkkijonot
- ks Guide
Merkkijonot ovat olioita, joilla mm. seuraavia metodeja:
Merkkijonoja voi operoida seuraavilla operaattoreilla:
+ Liittää merkkijonot yhteen < > <= >= == Vertailee aakkosjärjestystä s[n] Antaa merkkijonon s n:nnen kirjaimenMerkkijonoja voi siis käsitellä kuin taulukoita eli merkkijono.charAt(0)
on sama kuin merkkijono[0]
Merkkijonoja voidaan Javascriptissa yhdistellä yksinkertaisesti +
-operaattorilla
let foo = "tämä" + "tämä"
Myös taulukosta voi helposti tehdä merkkijonon ja käyttää haluttua erotinmerkkiä
let foo = ["teksti1","teksti2", "teksti3"]
console.log( foo.join(";") );
Merkkijonojen tyyppien muunnoksiin on olemassa muutama globaali funktio:
let luku = parseInt("567");
let luku = parseInt("567", 10); // toinen argumentti kertoo kantaluvun. Tässä kymmenjärjestelmä
let luku = parseInt("0567"); // ei toimi kuten voisi kuvitella. etunolla tarkoittaa, että luku saatetaan käsitellä oktaalijärjestelmässä.
let luku = parseInt("0567", 10); // tämä toimii
let luku = parseInt("101", 2); // binääriluku
5.5 Ehtolauseet
5.5.1 if...else:
if (ehto) { jos oli tosi... } else { jos oli epätosi... }
5.5.2 switch
switch (expression) { case label_1: statements_1 // break; case label_2: statements_2 // break; // ... default: statements_def }
Avainsana else
kuuluu samalle riville sulkujen } ja { kanssa. –Tyylipoliisi
5.5 Silmukat
for- ja while-silmukat toimivat kuten Javassa.
Labelilla voi nimetä tietyn loopin jolloin voi break- tai continue-komennolla viitata tähän looppiin.
ulompi: while(true) { console.log('ulompi silmukka'); let x = 0; while(true) { console.log('sisempi...'); x = x + 1; if ( x > 10) { break ulompi; } } }
5.6 for..in ja for..of
for..in ja for..of toimivat hieman eri tavoilla.
Note: for...in should not be used to iterate over an Array where the index order is important. Millainen esimerkki tähän sopisi? Eikös Array indeksi ole aina numeerinen ja järjestyksessä?
—for..in käy läpi taulukon avaimet eli alkioiden paikkanumerot taulukossa ja myös itse määriteltyjen attribuuttien nimet. for..of käy läpi oikeat taulukon arvot
5.5 map, reduce, filter, every
Esim. taulukoille on tarjolla metodit map
, reduce
, filter
, every
, ...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
—5.6 Poikkeukset
try { kokeillaan jotain ... // throw 'no ny sekos'; } catch (e) { tuli poikkeus... console.log(e); }
5.7 Promise
Käytetään asynkronisten funktioiden yhteydessä. Tähän palataan TIES4080-kurssilla.
5.8 Taulukot
Taulukko luodaan Array-oliolla
let paikat = new Array(); paikat[0] = "Jämsä"; paikat[1] = "Äänekoski";
tai hakasulkeilla:
let paikat = ["Jämsä", "Äänekoski"];
- Taulukon indeksinä on aina numero.
- Taulukon viimeistä seuraavan indeksin saa taulukko.length -metodilla.
-
Huom.
paikat[100] = "Helsinki";
length on nyt 101 eikä 3!
Taulukkoon lisääminen onnistuu seuraavasti:
paikat[paikat.length] = "Jyväskylä"; paikat.push("Jyväskylä");
Taulukko on kuten Object, mutta taulukolle on määritelty length
Taulukot ovat oikeasti osoittimia. Taulukkoa ei voi kopioida pelkällä sijoitusoperaatiolla. kts. Array.from ja slice, jotka tekevät shallow-kopion taulukosta. Jos haluaa oikean kopion, niin kopiointi on ohjelmoitava itse.
5.8 Delete vs. splice
JavaScript-taulukosta poistaminen tapahtuu splice-metodilla.
On olemassa myös delete
-operaattori, joka poistaa ominaisuuksia objekteilta. Taulukon alkioiden yhteydessä tämä tarkoittaa käytännössä taulukon alkion vaihtamista undefined
-tyyppiseksi. Taulukon koko tai indeksointi ei muutu, jos käyttää delete
-operaattoria. Delete on tarkoitettu objektien ominaisuuksien poistamiseen eikä taulukon alkioiden poistamiseen.
Taulukon alkiot voi helposti yhdistää join()
-metodilla.
5.8 Set
Set on taulukko johon voi tallentaa vain uniikkeja arvoja.
5.8 Map
Map on tietorakenne johon voidaan tallentaa avain-arvo-pareja. Vrt. Python dict. Myös Javascriptin omat objektit toimivat vastaavanlaisena tietorakenteena.
6. Funktiot
JavaScriptin funktiot ovat oikeastaan proseduureja, sillä ne voivat palauttaa tai olla palauttamatta paluuarvoa. Lisäksi funktiot voivat aiheuttaa sivuvaikutuksia. Funktion esittelyssä määritellään funktion nimi, sekä funktion parametrien nimet. Parametrien tyyppejä ei tarvitse kertoa, sillä (käytännössä) kaikki arvot JavaScriptissä ovat olioita. Parametrit ovat siten viitteitä olioihin.
Javascriptin funktiokutsuissa on oletuksena käytössä pass by value, paitsi jos parametreina on objekteja tai taulukoita jolloin toimii pass by reference.
Funktion voi esitellä seuraavasti:
Huomioitavaa:
- Funktiota voi kutsua ylimääräisillä parametreilla. Kaikki funktion saamat parametrit voi käydä läpi arguments-taulukolla.
- Jos funktio ei palauta return-lauseella arvoa on funktion palautusarvo undefined
- Arrow functions
JavaScriptissä ei ole funktion kuormitusta, vaan parametrien arvon olemassaolon joutuu itse testaamaan:
edellä voitaisiin käyttää myös muotoa:
return a + (maara || 1); // HUOM! Toimii tässä väärin!
mutta jos
maara
on 0, niin silloinkinm
saa arvon yksi. Eli se ei sovi tähän esimerkkiin.
7. Objektit
Assosiatiivisia taulukoita (nimi-arvo-pareja) voi tehdä seuraavasti (vrt. Map):
Tämä alku on kyllä harhaanjohtava. Assosiatiiviset taulukot (vrt. pythonin dict) tehdään nykyään Map-oliolla. Oliot olioina ja mapit mappeina. (Korjataan kun ehditään.) -ji
—Jonne, ei pidä paikkaansa. Assosiatiiviset taulukot voidaan tehdä Map-oliolla, mutta käytännössä näin ei kuitenkaan tehdä. Esim. JSON-muotoista dataa käsiteltäessä ei Mapia käytetä vaan aina kyseessä ovat objektit.
—Jep, JSONille hyväksyisin tuon, mutta muuten kannattaisikäyttää Map’ia. Ks. Map vs. Object MDN:stä. -ji
—Toki kannattaisi käyttää Mapia, mutta käytäntö on vaan ihan eri.
—Käytäntö on mitä on, mutta sekin voi parantua. On typerää pysyä vanhoissa huonoissa tavoissa vain tavan vuoksi.
—Niin kauan kuin JSON-muotoista dataa liikutellaan on pakko käyttää objekteja. Javascriptin oma JSON.stringify ei osaa muuntaa Map-olioita JSON-muotoon.
—Objektin sijoitus muuttujaan tarkoittaa objektiin viittaavan viitteen sijoitusta muuttujaan. Objektia ei voi siten kopioida pelkällä sijoitusoperaatiolla. Katso Object.assign(), jos haluat tietää, kuinka objektista tehdään matala (shalllow) kopio.
Yllä olevan esimerkin ssosiatiivinen taulukko säätilat
on itseasiassa objekti, jolla on attribuutteja. Tämä voi aiheuttaa jossain tilanteissa hämmennystä. Vrt. Map
JavaScript (joka pohjautuu ECMAScript 3 -standardiin) on prototyyppi-pohjainen kieli ja siinä ei ole luokkia samassa mielessä kuin Java/C++/C#-kielissä vaan pelkästään olioita (objekteja).
- JavaScriptissä on vain olioita, ei luokkia. Jos huomaat ajattelevasi luokkia, lepää hetki, poista luokat mielestäsi, ja jatka eteenpäin.
- Uusimmassa JavaScriptissä (EcmaScript 6) on
class
-avainsanalla merkitty rakenne olioiden ja prototyyppien esittelyyn, vaan (onneksi) ei vieläkään luokkia. - Jokaisen olion piirteet ovat joko sen omia, tai sen prototyyppiolion omia. Lisäksi ne ovat dynaamisia, eli niitä voi lisätä ja poistaa ajon aikana.
- JavaScriptissä funktiotkin ovat olioita.
- ... ja funktiot ovat paremminkin proseduureja, sillä ne voivat olla palauttamatta paluuarvoa ja aiheuttaa sivuvaikutuksia.
JavaScriptissä omia olioita voidaan luoda seuraavasti:
Objekteja laajennetaan toisten objektien avulla käyttäen prototype-määritystä. Private-attribuutteja ja -metodeja on mahdollista luoda pienellä vaivalla.
// muistakaa, että attribuutteja (avaimia) voi vapaasti keksiä let testi = new Object(); undefined testi.foo; undefined testi.foo==undefined true testi.foo = "koe"; "koe" testi.foo==undefined; false delete testi.foo; true testi.foo==undefined; true // muistakaa, että objekteilla testi.bar on sama asia kuin testi["bar"] testi["bar"] = "koe2"; "koe2" testi.bar; "koe2" testi.bar==undefined; false delete testi["bar"]; true testi.bar==undefined; true
7.1 Olion alustus vanhalla tavalle
HUOM! Katso uudempaa käyttöä seuraavan class-luvun nykyisin suositeltava tapa. Tämä vanha tapa esitetään tässä, koska (vanhassa) koodissa tätä vielä näkee paljon ja se on syytä tarvittaessa tunnistaa.
Olion luomista varten on tehtävä olion rakenninfunktio, jonka nimeä käytetään puhuttaessa yleisesti funktiolla luoduista olioista. Vertaa, miten Javassa tai C#:ssa alustajametodin nimi on sama kuin luokan nimi.
Jos tätä rakenninfunktiota kutsutaan muodossa new FunktionNimi(param)
on funktion määrittelyssä käytettävissä this
-viite olioon, jonka arvon new palauttaa.
Tämän jälkeen voidaan lisätä metodit lisaa
ja toString
olion prototyyppiin. Jos metodit lisättäisiin kuten attribuutit, ne monistuisivat jokaiselle oliolle. Prototyyppiolio, jonka new
-operaattori kopioi, löytyy aina rakentajafunktion attribuutista prototype
.
Seuraavalla kolmella rivillä testataan laskuria. Ensin luodaan laskuriolio, sen arvoa kasvatetaan kahdesti, ja sitten olio tulostetaan konsoliin.
Sitten luodaan HienoLaskuri
, jotta opitaan toisen olion ”perintä”, tai tarkemmin sanottuna metodikutsun delegointi prototyypin prototyypille. Ensin määritellään rakenninfunktio HienoLaskuri(kohde, arvo)
.
Seuraavilla riveillä sidotaan HienoLaskuri
Laskuriin
, eli tässä se varsinainen ”perintä” vasta tapahtuu. HienoLaskuri
-olion prototyypiksi luodaan tavallinen Laskuri
-olio, joka kopioidaan aina new
-operaattorilla, ja alustetaan kuntoon HienoLaskuri
-rakentimella. Koska uuden Laskuri
-olion sijoitus prototyypiksi muuttaa HienoLaskuri.constructor
-attribuutin osoittamaan Laskuri
-rakentimeen, tulee se korjata osoittamaan takaisin rakentimeen HienoLaskuri
.
Ja lopuksi taas kokeillaan, miten HienoLaskuri
toimii.
7.2 class
EcmaScriptin uusin versio tuo mukanaan class
-avainsanan, jota voi käyttää olion rakentimen ja prototyypin metodien esittelyyn. Tämä selkiyttää huomattavasti koodia. On kuitenkin syytä muistaa, että tämä on vain syntaktista sokeria, sillä ns. luokka on prototyyppiolio kuten ennenkin, ainakin toistaiseksi.
7.3 Jos todella haluat ymmärtää
Jos todella haluat ymmärtää, mistä JavaScriptin prototyyppioliomallissa on kyse, suosittelen lukemaan Douglas Crockfordin kirjoituksen aiheesta Classical inheritance in JavaScript.
7.4 Funktiokin on olio
JavaScriptissä funktiotkin ovat olioita. Tämä tarkoittaa sitä, että funktioilla voi olla attribuutteja ja metodeita. Ne tekee funktioiksi se, että ne osaavat vastata funktion sovittamisviestiin ()
. Alla on esimerkki funktiosta oliona.
8. Tarpeellisia funktioita
8.1 Array.sort()
Javascriptin taulukoita järjestettäessä täytyy itse kirjoittaa oma vertailufunktio (compareFunction), jos taulukoissa on esim. objekteja tai muuta monimutkaisempaa sisältöä. Jos on huolimaton tämän funktion kanssa niin ampuu helposti itseään jalkaan. Väärin kirjoitettu funktio voi tuurilla toimia firefoxissa, mutta ei toimikaan esim. Chromessa.
Jos vertaillaan numeroita niin vertailufunktion voi kirjoittaa lyhyesti näin:
function compareNumbers(a, b) { return a - b; }
Jos a ja b ovatkin stringeja niin ylläoleva funktio ei toimikkaan oikein.
Jos vertaillaan lähes mitä tahansa muuta kuin numeroita niin funktion ON oltava seuraavaa muotoa:
function compare(a, b) { if (a is less than b by some ordering criterion) { return -1; } if (a is greater than b by the ordering criterion) { return 1; } // a must be equal to b return 0; }
Suositeltavaa on käyttää aina tätä jälkimmäistä niin ei vahingossa satu omaan jalkaan.
8.1 Date
8.1.1 Päivämäärä
let aika = new Date(); // Huono tapa console.log(aika.getDate() + "." + (1+aika.getMonth()) + "." + (1900+aika.getYear())); // Parempi tapa console.log(new Intl.DateTimeFormat('fi-FI').format(aika));
8.1.2 Kulunut aika
let aika = new Date(); let hetkiA_msec = aika.getTime(); // tehdään jotain let hetkiB_msec = aika.getTime(); let kulunutaika = new Date(hetkiB_msec - hetkiA_msec); alert(kulunutaika.getSeconds());
8.1 Pyöristäminen ja numeroiden muotoilu
let liukuluku = 3.245200004; let kaksidesimaalia = Math.round(liukuluku*100)/100
Numeroiden mutoilu on syytä tehdä Intl.NumberFormat-avulla.
8.1 isNaN
Tutkii onko muuttuja erikoisarvoa NaN (not a number). NaN-arvoa ei voi vertailla muulla kuin tällä funktiolla.
let numero = parseInt(document.getElementById("tekstikentta").value); if (isNaN(numero)) document.getElementById("tekstikentta").className = "red";
8.2 typeof
Operaattorit: typeof - Core JavaScript 1.5 Reference
Palauttaa merkkijonona olion tyypin. Älä käytä liikaa!
9. JSON
Javascriptin tietorakenteet ovat lähes sama asia kuin JSON-tiedostomuoto.
JSON on standardoitu tiedostomuoto tiedonvälitykseen. JSON on suoraan javascript-yhteensopiva mutta sitä käytetään usein monen muun kielen yhteydessä. WWW-sovelluksissa JSON on erittäin yleinen tiedonsiirtomuoto.
Voit käyttää JSONina suoraan javascriptin taulukoiden ja objektien esitysmuotoja eli [] ja {} sisältämät osat:
// javascriptia let a = [1,2,3,4]; // JSONia [1,2,3,4]
Kokeile tutkia seuraavia tietorakenteita JSON-editorilla: data ja tupa.
Vastaavia rakenteita voi tutkia myös suoraan selaimen konsolissa. Avaa pohja.html-tiedosto ja konsoli.
10. Tietorakenteiden käsittelyä
Kätevämpää kuin tuo indeksikikkailu olisi tehdä opiskelijasta kunnollinen olio. Jätetään se harjoitustehtäväksi.
11. If-lauseiden välttäminen monimutkaisissa ehdoissa
Joskus voi olla asioita jotka riippuvat hyvin monimutkaisella tavalla ympäröivistä ehdoista. Tällöin voi käyttää päätöstauluja. Oletetaan esimerkiksi, että on ehtoja:
- sataa
- paljon
- lämmin
ja halutaan noiden ehtojen perustella saada tieto kannattaako lähteä pyöräilemään. Ensin kirjoitetaan totuustaulu kaikille vaihtoehdoille ja niiden perusteella että lähdetäänkö pyöräilemään:
n | sataa | paljon | lämmin | pyöräilemään | muuta |
---|---|---|---|---|---|
0 | F | F | F | T | |
1 | F | F | T | T | |
2 | F | T | F | T | ei mahdollinen |
3 | F | T | T | T | ei mahdollinen |
4 | T | F | F | F | |
5 | T | F | T | T | |
6 | T | T | F | F | |
7 | T | T | T | F |
Vaikka tämän totuustaulun mukaan olisikin vielä tehtävissä if-lauseilla vastaava ehto pyöräilyyn lähtemiselle, niin jos ehtojen määrä kasvaa tuosta kolmesta, niin if-lauseesta tulee vaikeasti ymmärrettävä ja ylläpidettävä. ei mahdollinen
-tilanteissa ei ole väliä mitä totuustauluun kirjoitetaan, koska sellainen tilanne ei voi tulla.
Taulukon alkuun on kirjoitettu n, joka voidaan ajatella luvuksi, mikä muodostuu jos ehtojen joukko ajatellaan binääriluvuksi. Edellä esimerkiksi:
T F T = 1 0 1 = 5
Kirjoitetaan nyt sama helppotajuisesti ylläpidettäväksi JavaScript koodiksi:
Samaa kikkaa voi sitten soveltaa, jos esimerkiksi tuossa pitäisi tuloksen lisäksi palauttaa tieto siitä puetaanko paljon (2) vai vähän (1) ja tuleeko sadekengät (2). Silloin boolean paluuarvon sijaan palautettaisiin vaikkapa olio (tai tarvittaessa taulukko), jossa on vaatetus:
Kuten edellä, ei oikeastaan ole väliä mikä vaatetus palautetaan jos ei olla lähtemässä pyöräilemään. Toki tuota voisi soveltaa niin, että pyöräilyn "vastakohtana" on kävely ja palautetaan sitten sitä vastaava vaatetus. Kokeile muuttaa edellistä siten.
Oikeasti vaatetus ja kengät tietona kannattaisi palauttaa jotakin kuvaavampaa kuin kokonaisluku. Tässä on vaan koitettu pitää esimerkki yksinkertaisena. Kokeile muuttaa edellistä siten, että vaatetus palautetaan merkkijonona, samoin kengät.
Seuraava askel tästä on laittaa taulukkoon lambda-funktioita.
12. Materiaalia
- Eloquent JavaScript - Interaktiivinen, eli esimerkit ovat ajettavissa ja muokattavissa, opas JavaScriptin opiskeluun.
- Javascript First Steps
- A re-introduction to JavaScript
- JavaScript Guide
- JavaScript reference
- Introduction to events
- Understanding Javascript OOP
- JS vs Python
12.1 Muita JS-linkkejä
- https://medium.freecodecamp.org/the-complete-javascript-handbook-f26b2c71719c
- https://medium.freecodecamp.org/how-you-can-improve-your-workflow-using-the-javascript-console-bdd7823a9472
- https://developer.mozilla.org/en-US/docs/Web/API/console
- https://stackoverflow.com/questions/5873810/how-can-i-get-last-characters-of-a-string-using-javascript
- Table Fixed Autoscroll
- https://stackoverflow.com/questions/34045777/copy-to-clipboard-using-javascript-in-ios
- https://pegjs.org/online = JavaScript parser tool
- https://docs.replit.com/tutorials/15-repl-chat - chat Node.js ja websocket
- https://blog.stackblitz.com/posts/introducing-webcontainers/
These are the current permissions for this document; please modify if needed. You can always modify these permissions from the manage page.