Andrise programmeerimisalane WIKI
Objektid ja objektorienteeritud programmeerimine JavaScriptis
Mõnikord arvatakse, et JavaScript pole objektorienteeritud keel, kuid paraku on see ekslik ning kaugel tõest - JavaScript koosnebki peamiselt just objektidest ning pakub objektorienteeritud programmeerimiseks piisavalt võimalusi. JavaScripti prototüübipõhine objektorienteeritus võib küll näida paljudele esimese pilguga harjumatu ja võib olla ka arusaamatuna - puuduvad ju näiteks klassid kui sellised (sellest ka ehk eksiarvamus, et JavaScript pole objektorienteeritud), samuti on võib olla harjumatu prototüübiline delegeerimine. Tegelikkuses aga on JavaScripti OO üllatavalt võimekas, suutes pakkuda palju sellist mida oodatagi ei oskaks.
Omadused ja meetodid
Objektid on JavaScriptis erinevad võtme-väärtuse paaride kogumid. Võtit nimetatakse objekti omaduseks ning selle väärtuseks võib olla näiteks lihttüübiline väärtus (number, string, loogikaväärtus) või mõni teine objekt (sh. massiiv või funktsioon). Objekti omaduste juurde pääseb läbi punktnotatsiooni kus punkt eraldab objekti ning selle omadust.
objekt.pikkus = 50;
Kui omaduse väärtuseks on funktsioon, nimetatakse seda omadust objekti meetodiks.
window.alert(123);
Siin on alert objekti window meetodiks.
Teise võimalusena saab objekti käsitleda ka assotsiatiivse massiivina, millisel juhul tuleb punktnotatsiooni operaator . asendada nurksulgudega. Kuna nurksulud võtavad sisendiks erinevalt punktnotatsioonist omaduse enda asemel omaduse nime tekstikujul, saab seega dünaamiliselt (stringi muutes) määrata missugust väärtust küsime.
var tyyp = "pikkus"; objekt[tyyp] = 50; alert(objekt[tyyp]); // Väljastab: 50
Objekti omadusi ja meetodeid saab kasutada nagu tavalisi muutujaid. Nad tagastavad mingi väärtuse, neile saab omistada uut väärtust ning neid saab kasutada funktsioonile edastatava parameetrina. Omadusi ja meetodeid saab objektile luua lihtsalt neile väärtust andes. Näiteks kui meil on objekt maja, millele me tahame lisada omadust katus ning omistada sellele mingi väärtuse, saame seda teha järgnevalt:
maja.katus = "plekk";
Objektile maja lisatakse omadus katus, mille väärtuseks saab plekk.
Sarnaselt saab lisada ka meetodeid.
maja.misKatus = function(){ return this.katus; } alert(maja.misKatus());
Kontrollimaks, kas objekt sisaldab mingit omadust või meetodit, saab kasutada operaatorit in.
if("misKatus" in maja){ alert(maja.misKatus()); //käivitatakse ainult juhul, kui selline meetod on objektis olemas }
Objekti kõikide omaduste ja meetodite loetlemiseks, saab kasutada struktuuri for in. Struktuur väljastab ükshaaval kõik objektis olevate omaduste ja meetodite nimetused. Kusjuures järjestus on suhteliselt juhuslik - lisatud omadused paiknevad objektis nii nagu konkreetses arvutis on parasjagu vaba mälukohti olnud. Reeglina tulevad omadused küll lisamise järjekorras, aga see järjekord ei ole garanteeritud.
for(var i in maja){ alert(i); }
Omaduse ja meetodi kustutamiseks objektist saab kasutada operaatorit delete.
delete maja.katus; alert(maja.katus); // undefined
Meeles tuleb pidada, et kustutamisel operaatoriga delete, ei kustutata mälust väärtust ennast, vaid objektis olev viide selle väärtuse juurde.
Objekti loomine
Objekti saab luua kahel viisil. Esiteks saab selle luua läbi oroperaatori new, mis loob operaatorist paremal olevast konstruktorfunktsioonist uue isendi.
var objekt = new Object(); var aeg = new Date(); var regulaaravaldis = new RegExp();
Operaator new loob uue tühja objekti ning seejärel käivitab funktsiooni, edastades funktsioonile viite this äsja loodud uue objekti juurde. Konstruktorfunktsioon on mõeldud uue objekti algväärtustamiseks vajalike väärtuste ja tegevustega.
Teiseks saab kasutada objektiliteraale, mis kujutavad endast loogelisi sulge.
var objekt = {};
Objektiliteraal sisaldab komadega eraldatud võtme-väärtuste paare, kus võti (omadus või meetod) ja väärtus on omakorda eraldatud kooloniga. Omaduste nimed saab literaalis esitata nii nimetusena kui ka stringina ning omaduse väärtuse saab määrata suvalise avaldisega - omaduse väärtuseks saab teostatud avaldise poolt tagastatud väärtus.
Objektiliteraale on lubatud ka pesastada, st. et literaalis defineeritud objekti omaduse väärtuseks võib omakorda olla uus objektiliteraal.
var objekt = { pikkus: 100, laius: 150, nurgad: { "alumine": Math.sin(45)*100, "ylemine": Math.sin(60)*50 } }
Järgmises näites emuleerime operaatori new töö mõistmiseks selle tegevust alternatiivsete meetodite abil. Loome funktsiooni, mis sisendiks saadud konstruktorfunktsiooni põhjal loob uue objekti ning seab selles kõik vajalikud väärtused, sealhulgas prototüübiahela.
// funktsioon uus, mis asendab operaatori new function uus(konstruktor){ var uus_objekt = {}; konstruktor.apply(uus_objekt, Array.prototype.slice.call(arguments).slice(1)); uus_objekt.__proto__ = konstruktor.prototype; uus_objekt.constructor = konstruktor; return uus_objekt; } // konstruktorfunktsioon function Objekt(andmed){ this.andmed = andmed; } Objekt.prototype.teata = function(andmed){ alert(this.andmed); } // loome konstruktorfunktsiooniga uue objekti, kasutades operaatori new asemel funktsiooni uus var objekt = uus(Objekt,"sisu"); objekt.teata(); // "sisu"
Näites emuleerib funktsioon uus operaatori new tegevust. Funktsioon saab parameetriks konstruktorfunktsiooni ning sellele edastatavad parameetrid.
Esiteks loob funktsioon lokaalsesse skoopi tühja uue objekti objektiliteraali abil
var uus_objekt = {};
millest saabki funktsiooni täitmise lõpus tagastatav objekt. Seejärel käivitame konstruktorfunktsiooni, määrates funktsiooni meetodiga apply objektiviiteks loodud objekti ning parameetriteks kõik funktsioonile uus edastatud parameetrid.
konstruktor.apply(uus_objekt, Array.prototype.slice.call(arguments).slice(1));
Kuna esimene parameeter on konstruktorfunktsioon ise, tuleb see argumentide nimekirjast eemaldada. Kuna aga arguments parameeter pole massiiv vaid massiivilaadne objekt, puuduvad selles operatsiooni läbiviimiseks vajalikud meetodid. Seega tuleb tuleb arguments kõigepealt massiiviks teisendada, mida saame teha läbi Array objekti meetodi slice.
Järgmiseks määrame ära loodud objekti prototype viite, milleks saab konstruktorfunktsiooni prototype objekt. Kasutame selleks objekti peidetud omadust __proto__.
uus_objekt.__proto__ = konstruktor.prototype;
Ja viimase sammuna märgime ära objekti konstruktori, milleks saab kasutataud konstruktorfunktsioon.
uus_objekt.constructor = konstruktor;
Edasi ei jää muud, kui loodud objekt tagastada väljastuskohta, kus seda saab kasutada täpselt samamoodi, kui operaatoriga new samast konstruktorfunktsioonist loodud objekte.
Objektide kettimine
Tihtipeale on mugav teha ühe objektiga mitu tegevust korraga. JavaScriptis võimaldab seda objektide kettimine, kus ühe ja sama objektiga viiakse korraga läbi mitmeid erinevaid tegevusi.
Juhul kui objekti erinevate meetodite tagastusväärtuseks on viide this või mõni muu objekt, saabki neid meetodeid vajadusel mugavalt üheks pikaks lauseks kokku kettida.
var objekt = { esimene: function(nr){ alert(1*nr); return this; }, teine: function(nr){ alert(2*nr); return this; }, kolmas: function(nr){ alert(3*nr); return this; } } objekt.esimene(3).teine(3).kolmas(3); // 3, 6, 9
Kasulik on see näiteks juhul, kui on tarvis seada korraga objekti erinevaid väärtusi. Samuti kasutavad antud võimalust laialdaselt erinevad JavaScripti raamistikud, näiteks Prototype ja jQuery - teoreetiliselt on jQuery raamistikku kasutades võimalik kirjutadagi ainult ühe lausega terve JavaScripti programm. Loetavusele võib antud lähenemine mõjuda muidugi ekstreemsematel juhtudel üsnagi laastavalt, seega tasub objektide kettimist kasutada pigem konservatiivselt.
this
this pseudomuutuja viitab hetkel aktiivsele objektile. Tegu on alternatiiviga objekti enda nimele, võimaldades funktsioonil saata teateid objektile, mille meetodiks ta ise on. Näiteks konstruktorit defineerides ei pea seega teadma lõpliku objekti nime, mis konstruktori abil luuakse.
Funktsioonides on this seotud ühega järgnevatest:
- Objektiga, millega funktsioon on seotud kui tegu on konstruktorfunktsiooni või objekti meetodiga
- Meetoditega
callvõiapplyfunktsioonile edastatud objektiga - Kõikidel muudel juhtudel globaalse objektiga (brauserites on selleks
window), sh. näiteks anonüümsetes funktsioonides, mis on defineeritud konstruktorfunktsioonide ning objektide meetodite skoobis
function Konstruktor(){ this.a = 1; function b(){ this.a = 2; } b(); alert(this.a); // 1 } new Konstruktor(); alert(a); // 2
Eelnevas näites on lause this.a = 1; korral this seotud konstruktorfunktsiooni loodud objektiga, funktsioonis b oleva rea this.a = 2; puhul aga on this seotud globaalse objektiga window. Kuna globaalse objekti puhul ei ole vaja muutujat this ega window eraldi märkida, saabki muutuja a väärtuse lugemiseks kasutada otsepöördumist real alert(a).
Sisuliselt on programmi skoop lahendatud järgmiselt
with(window){ // JavaScripti programm }
Seega ongi võimalik kasutada näiteks this.alert() või window.alert() (globaalses skoobis this === window) asemel lihtsalt funktsiooni nimetust alert().
Kuna funktsioonide skoobis defineeritud funktsioonides on this seotud globaalse objekti külge, on reeglina vaja kuidagi viidet originaalse objekti juurde. Selleks on võimalik kasutada sulundis kehtivad lokaalset muutujat. Viite saamiseks omistame this konstruktorfunktsioonis või objekti meetodis lokaalsele muutujale ning skoobis defineeritud sulundfunktsioon saab seda muutujat kasutada soovitud objekti viidana.
function Konstruktor(){ this.a = 1; var that = this; function b(){ that.a = 2; } b(); alert(this.a); // 2 } new Konstruktor(); alert(a); // undefined, muutuja a on defineerimata
Konstruktorfunktsioonid
Konstruktorfunktsioonide nimetused esitatakse reeglina suure algustähega. Tegu ei ole keelelise süntaksiga, mis eiramisel annab veateate, vaid võttega koodi loetavamaks tegemisel. Näiteks aitab see vältida vigu, kus konstruktorfunktsiooni kasutatakse ilma operaatorita new. Programm töötab sellisel juhul tõrgeteta (konstruktorfunktsioon on siiski lihtsalt üks eritüübiline funktsioon, mida saab ka niisama käivitada), ainult et tõenäoliselt ei tee programm seda, milleks ta plaanitud on.
var Konstruktor = function(andmed){ this.andmed = andmed; }
Kui me nüüd kasutame konstruktorfunktsiooni Konstruktor koos operaatoriga new, loome sellega uue objekti, mille argumendi andmed väärtuseks saab objekti loomisel funktsioonile antud parameetri väärtus.
var objekt = new Konstruktor(123); alert(objekt.andmed); // 123
Kui me teeme sama ilma operaatorita new, saame oodatult veateate.
var objekt = Konstruktor(123); alert(objekt.andmed);
Kuid veateade ei tule esimeselt realt var objekt = Konstruktor(123); - seal on kõik korrektne, konstruktorfunktsioon käivitatakse lihtsalt tavalise funktsioonina. Veateate annab hoopis teine rida alert(objekt.andmed);.
Nimelt tagastab funktsioon alati mingi väärtuse. Juhul kui funktsiooni on kasutatud konstruktorina koos operaatoriga new on tagastusväärtuseks viide funktsiooni loodud isendi juurde - this. Kui funktsiooni on kasutatud ilma operaatorita new ning funktsioonis puudub väärtust tagastav lause return, on tagastusväärtuseks eriväärtus undefined.
Seega muutuja objekt väärtuseks saab esimesel real undefined ning kui me järgmisel real üritame lugeda objekti omaduse andmed väärtust, saamegi veateate. Eriväärtus undefined ei ole käsitletav objektina ja seega ei saa sellel olla ka omadusi ega meetodeid.
Aga mis juhtub funktsiooni deklaratsioonis oleva lausega this.andmed = andmed;? Milline viide this on sel puhul kasutuses - eelnevalt selgus, et operatoorit new kasutamata viidet this funktsiooni isendi juurde ei looda. undefined väärtuse korral aga annab interpretaator omadustega opereerimisel veateate.
Juhul kui funktsioonil puudub viide this enese objekti juurde, viitab this globaalse skoobi objektile. Brauseri puhul on selleks globaalse skoobi objektiks window. Seega järgnev lausejada koos window objektiga, on täiesti korrektne ja töötav.
var objekt = Konstruktor(123); alert(window.andmed); // 123
Seda, kas funktsioon on hetkel käivitatud tavalise funktsiooni või konstruktorina, saab kontrollida järgnevalt
function x(y){ if (this.constructor == x) alert('käivitatud konstruktorina'); else alert('käivitatud funktsioonina'); }
või
function x(){ if ((this instanceof arguments.callee)) { alert("käivitatud konstruktorina"); } else { alert("käivitatud funktsioonina"); } }
Konstruktorfunktsioon saab olla ka anonüümne. Sellisel juhul tuleb funktsioon deklareerida koos operaatoriga new. Kuna operaator new ootab operandiks funktsiooni, ei ole vahet, kas selleks on mõni nimeline funktsioon või anonüümse funktsiooni deklaratsioon. Sellist anonüümset konstruktorit tasub kasutada juhul, kui soovime luua vaid ühte objekti, mis aga algväärtustamisel peaks sooritama mingeid kindlaid tegevusi.
var flash = new function(){ this.installed = false; this.version = -1; //... kontrolli kas flash on brauseris toetatud //... ja leia üles flashi versiooni number } if(flash.installed){ //... lisa lehele flash objekt }else{ document.write('Kahjuks sinu brauser ei toeta Flashi'); }
Näites tuvastame Flash mooduli toe brauseris ning omistame sellega seotud väärtused loodavale objektile flash. Kui edaspidi on lehel vaja Flashi olemasolu kontrollida, on vastav informatsioon juba objektis flash olemas.
Prototüübid ja delegeerimine
JavaScript erineb teistest objektorienteeritud programmeerimiskeeltest peamiselt klasside ning seega ka klassidevahelise pärimise puudumisega - kuigi keeles on olemas reserveeritud nimetus class, pole JavaScript mitte harjumuspäraselt klassipõhine programmeerimiskeel, vaid hoopis prototüübipõhine. Prototüübipõhistes keeltes on klassilaadseid struktuure võimalik emuleerida (vastupidine on tunduvalt keerulisem, kui mitte võimatu), kuid see tähendab täiendava vahekihi loomist, mis alati pole võibolla otstarbekas.
Kui klassipõhises keeles defineeritakse esiteks klass ning klassi põhjal luuakse objektid, mis erinevad vaid omaduste väärtuste poolest (olles sisuliselt üksteise identsed koopiad), siis prototüübipõhises keeles tuletatakse objektid teistest objektidest, niiöelda prototüüpidest. Igale objektile eraldi on võimalik määrata tema poolt kasutatavad omadused ja meetodid ning ühisest prototüübist tuletatud objektid võivad üksteisest üsna palju erineda.
Huvitaval kombel on JavaScript koos teiste ECMAScript dialektidega sisuliselt ainsad laiemas kasutuses olevad prototüübipõhised keeled. Enamus teisi sarnaseid keeli on kas praktiliselt välja surnud (NewtonScript), või pole nad arendusest kaugemale jõudnudki (Kevo). JavaScripti üht suurimat mõjutajat, programmeerimiskeelt Self arendatakse endiselt edasi, kuid laialdast kasutust pole see senini leidnud.
Objektide kopeerimine
JavaScriptis puudub operatsioon objektide otseseks tuletamiseks teistest objektidest, seega võib tinglikult öelda, et JavaScripti puhul pole tegu ka päris ehtsa prototüübipõhise keelega. Selle asemel on keeles operaator new, mis loob uue objekti new ƒ() ning delegeerib loodava objekti omadused ja meetodid konstruktorfunktsiooni prototüüpobjektile ƒ.prototype. Sellise disainiga on üritatud veidigi läheneda klassipõhisele keelele, esitades prototype objekti kui omamoodi klassi, mille alusel saab luua uusi klassi isendeid. Paraku on sellega tekitatud ainult segadust, juhtides tähelepanu eemale JavaScripti tõelisest prototüübipõhisest olemusest.
copy
Õnneks on JavaScript väga paindlik ning üsna lihtsalt saab puuduvad operatsioonid asendada. Näiteks keele ühe esivanema, programmeerimiskeele Self laadse operatsiooni copy saab realiseerida järgmise funktsiooniga
function copy(object) { function F() {} F.prototype = object; return new F(); }
Sellise funktsiooni abil saab iga objekt olla teise objekti prototüübiks, mis on üks prototüübipõhise objektorienteeritud keele aluseid. Funktsioon võtab sisendiks objekti ning väljastab objekti koopia. Koopia saamiseks luuakse uus konstruktorfunktsioon ning omistatakse selle prototüüpobjektiks F.prototype funktsiooni sisendobjekt object. Kui nüüd konstruktorist luua operaatoriga new uus objekt, mis tagastatakse funktsiooni tagastusväärtusena, saab loodud objekt enda käsutusse kõik konstruktori prototüüpobjekti ehk siis funktsiooni sisendobjekti object omadused ja meetodid. Kopeeritud objektide puhul saame muuta objekti omadusi ja meetodeid, ilma et need muudaksid originaalse objekti andmeid.
var a = {val: 123}; var b = copy(a); b.val++; alert(a.val); alert(b.val);
Omistamisoperaatoriga = objekte kopeerida pole võimalik, kuna omistamisel kopeerib JavaScript vaid primitiivseid andmetüüpe (number, loogikamuutuja, string). Objektide puhul omistatakse muutujale väärtuse asemel viit originaalse objekti juurde. Juhul kui eelmises näites oleks teisel real hoopis lause var b = a;, oleks mõlema alert funktsiooni väljund sama - 124. Kuna muutes objekti b, mis on viidaks objekti a juurde, muudame ka objekti a.
__proto__
Lisaks eelpool defineeritud funktsioonile copy on JavaScriptis võimalik objekte tuletada, muutes objektis olevat peidetud omadust __proto__. Antud omadus kujutab endast otsest viidet prototüüpobjekti juurde ning seda seades, saame määrata, millisele objektile antud objekt enda jaoks tundmatud pöördumised delegeerib.
var a = {omadus: 123}; var b = {}; b.__proto__ = a; alert(b.omadus); // 123
Kahjuks JScriptis (Microsofti brauseris Internet Explorer JavaScripti asemel kasutatav ECMAScripti dialekt) pole manipuleerimine peidetud omadusega __proto__ võimalik. Seega reaalelulistes rakendustes seda vormi kahjuks kasutada ei saa.
Prototüüpobjekt
Juhul kui objektil puudub mingi omadus või meetod - puudub seos objekti ja identifikaatori vahel, otsitakse identifikaatorit konstruktorfunktsiooni prototüüpobjektist. Prototüüpobjektis on objekti viit this seotud esialgse päringu saanud objekti juurde.
function Ring(){}; f.prototype.PI = 3.14; var ring = new Ring(); alert(ring.PI); //3.14
Objektil ring puudub omadus PI, seega delegeeritakse päring edasi prototüüpobjektile. Juhul kui ka seal vastav omadus puudub, delegeeritaks päring edasi Function.prototype objektile ning sealt Object.prototype objektile. Kui omadust ei ole tervest delegeerimisahelast leitud, tagastatakse väärtusena undefined.
Kui loodud objekt implementeerib ise mõne prototüüpobjektis oleva meetodi või kirjutab üle mõne omaduse, jääb prototüüpobjektis väärtus muutmata, jäädes edaspidi peidetuks. Väärtus on endiselt olemas, aga läbi loodud objekti sellele enam ligi pääseda ei saa. Samas kõik teised objektid, mis on loodud sama konstruktorfunktsiooni kaudu ning pole meetodit või omadust üle kirjutanud, saavad seda endiselt edasi kasutada.
Konstruktorfunktsiooni defineerimisel tuleks seega objektide ühised meetodid ning omadused siduda konstruktorfunktsiooni prototüüpobjektiga, mitte defineerida need konstruktorfunktsiooni sisemiselt näiteks sulunditena.
Sulundfunktsiooni
function Konstruktor(){ this.teade = function(tekst){ alert(tekst); } }
asemel tuleks kasutada prototüüpobjekti
function Konstruktor(){} Konstruktor.prototype.teade = function(tekst){ alert(tekst); }
Mõlemad variandid on programmi toimimise seisukohalt võrdsed, kuid sulundi puhul delegeerimise asemel kopeeritakse meetod teade igale konstruktorist tuletatud objektile. Kui meetod on aga seotud konstruktori prototüüpobjekti külge, meetodi pärimised objektilt delegeeritakse ühele ja samale prototüüpobjektile.
Sellisel lähenemisel on peamiselt kaks positiivset külge, esiteks hoitakse kokku mälu (omaduse või meetodi mitme realisatsiooni asemel tuleb mälus hoida vaid üht) ning teiseks on võimalik hiljem kõikide objektide käitumist korraga muuta. Kui defineerida ümber prototüüpobjektis olev meetod või omadus, muudab see automaatselt kõikide sellest prototüübist tuletatud objektide käitumist, kes pole vastavat meetodit või omadust üle kirjutanud. Sulundi korral tuleks aga sarnase tulemuse saavutamiseks muuta kõiki objekte ükshavaal.
Delegeerimine
Delegeerimine on mehhanism andmete (objekti omadused) ning käitumise (objekti meetodid) jagamiseks, mis võimaldab kinnistada objekti teate teeninduse teisele objektile.
See tähendab, et kui objektilt üritatatakse pärida mingit omadust või üritatakse rakendada meetodit, mis objektis puudub, delegeeritakse päring (objekti viit this jääb seotudks esialgse objektiga) objekti prototüübile, kes siis vastab päringule ise.
Kuna prototüüpobjekt on tõenäoliselt tuletatud mingist kolmandast prototüübist, edastab see vajadusel päringu edasi järgmise taseme prototüübile. Kui selliselt moodustunud ahelast päritut ei leita, saadetakse esialgsesse väljakutsekohta tagasi eriväärtus undefined.
Laiendamine
JavaScriptis on võimalik laiendada kõiki objekte, lisades või üle kirjutades objektide prototüüpobjektide meetodeid ja omadusi.
Konstruktor.prototype.meetod = function([params]){ //this }
Näiteks võime lisada kõikidele objektidele meetodi, mis väljastab ükshaaval objekti kõik loendatavad omadused ja meetodid.
Object.prototype.elemendid = function(){ var tulem = []; for(var i in this){ tulem.push(i); } alert(tulem.join(', ')); } var objekt = { number: 123, tekst: "see on tekst" } objekt.omadused(); // number, tekst, elemendid
Nagu näha, muutub ka meetod elemendid üheks loendatavaks elemendiks, seega tasub ettevaatlik olla JavaScripti põhiobjektidele (Object, Array, String jms) uute meetodite lisamisega. Kui mingi osa programmist sõltub lausestruktuurist for..in, võib see tekitada ootamatuid tulemusi.
Avalikud ja privaatsed omadused ning meetodid
JavaScriptis pole eraldi võtmesõna objektides privaatsete omaduste ning meetodite defineerimiseks. Peitmisefekti on võimalik siiski saavutada - kasutades sulundeid. Kui defineerime meetodis või konstruktorfunktsioonis lokaalse muutuja, saavad selle muutuja väärtust lugeda ning seada teised antud funktsiooni skoobis defineeritud meetodid.
Konstruktor = function(){ var kaitstud = 0; this.teade = function(){ alert(kaitstud++); } } var objekt = new Konstruktor(); objekt.teade(); // 0 objekt.teade(); // 1 objekt.teade(); // 2
Näites objekti meetod teade saab opereerida muutujaga kaitstud, kuid väljastpoolt objekti ja isegi seda meetodit, muutujale kaitstud mingitpidi ligi ei pääse. Meetodit teade nimetatakse privilegeeritud meetodiks, kuna pääseb privaatsele muutujale ligi.
Sarnaselt eelnevaga on võimalik defineerida ka privaatseid meetodeid.
Konstruktor = function(){ this.a = 0; var that = this; var kaitstudMeetod = function(){ alert(that.a++); }; kaitstudMeetod(); // 0 kaitstudMeetod(); // 1 }
Meetod on ligipääsetav ainult konkreetses skoobis.
Objektide meetodid
Kõik objektid saavad konstruktorina kasutatavalt globaalselt objektilt Object kaasa mitmeid „sisseehitatud“ meetodeid objekti väärtusega opereerimiseks. Erinevad konstruktorid võivad osa neist meetoditest küll vajadusel üle kirjutada (näiteks toString meetod on iga konstruktori korral tihti erinev), kuid vaikimisi on nad igal JavaScripti objektil, hoolimata kasutatavast konstruktorist, alati olemas.
constructor
Object object.constructor
Omadus constructor viitab konstruktorfunktsioonile, mille abil objekt on loodud. Seda omadust kontrollib näiteks operaator instanceof oma toimingute läbiviimisel.
var objekt = new Date(); objekt instanceof Date; //true objekt.constructor === Date; //true
toString
String object.toString()
toString meetod üritab teisendada objekti tekstikujule. Vaikimis on selleks midagi kujul [object Object], kuid erinevad objektid võivad selle meetodi üle kirjutada. Näiteks Date objekti meetod toString() tagastab hetke aja stringi kujul.
var aeg = new Date(); alert(aeg.toString());
Tulemuseks on
"Sat May 09 2009 12:44:28 GMT+0300 (EEST)"
Vajalik on meetod juhtudel, kui objekti üritatakse kasutada stringi kontekstis, näiteks kasvõi funktsiooni alert parameetrina, milleks oodataksegi stringi. Eelneva näite saab lühemalt kirja panna seega nii:
alert(new Date());
toLocaleString
String object.toLocaleString()
Meetod toLocaleString on mõeldud esitamaks toString meetodi väljundit arvestades kasutaja hetke lokaali. Konstruktoriga Object loodud objektide korral on see sama, mis toString meetodilgi, kui näiteks Number ja Date objektide puhul on lokaaliga juba arvestatud.
valueOf
Number object.valueOf()
Meetod sarnaneb toString meetodile, kuid erinevusega, et toString kutsutakse välja, kui on vaja objekt teisendada tekstikujule, siis valueOf meetod kutsutakse välja, kui objekti on vaja kasutada näiteks numbrilises kontekstis. Kui Object objektide korral ei tee see meetod suurt midag, siis näiteks Date objektides on tagastusväärtuseks objektis määratud aeg numbrilise ajatempli kujul (millisekundid alates esimesest jaanuarist 1970).
hasOwnProperty
Boolean object.hasOwnProperty(String nimi)
hasOwnProperty kontrollib meetodi või omaduse suhet objektiga. Juhul kui meetod või objekt on defineeritud konkreetses objektis, on tagastusväärtus tõene, kui see on aga saadud mõnelt teiselt objektilt prototype ahela kaudu või seda ei eksisteeri üldse, on tagastusväärtus väär.
var a = {tekst: "see on tekst"}; a.hasOwnProperty("tekst"); // tõene a.hasOwnProperty("valueOf"); // väär
propertyIsEnumerable
Boolean object.propertyIsEnumerable(String nimi)
Meetod tagastab tõese väärtuse, kui parameetrina kontrolliks antud meetodi või objekti nimetus stringi kujul on defineeritud kontrollitavas objektis ning see on loendatav - kaastakse for..in tsüklisse. Kuna kõik kasutaja defineeritud meetodid ja omadused on alati loendatavad (see on ka üks põhjus, miks Object.prototype objekti ei ole soovitatav ise üle kirjutada) ning mitteloendatavad elemendid tulevad objektini prototype ahelat pidi ehk need on defineeritud kuskil mujal, on meetodi tagastusväärtus reeglina alati sama mis hasOwnProperty korral.
isPrototypeOf
Boolean Object.isPrototypeOf(Object objekt)
isPrototypeOf meetod kontrollib, kas objekt on parameetrina saadud objekti prototüübiahelas.
var objekt = {}; Object.isPrototypeOf(objekt); //false Object.prototype.isPrototypeOf(objekt); //true Function.prototype.isPrototypeOf(objekt); //true objekt.constructor.prototype.isPrototypeOf(objekt); //true