Ha objektum-orientált nyelvekből érkeztél a javascript világába, amelyekben voltak nyilvános és privát metódusok, valószínűleg olyan programozási módhoz vagy szokva, amelyhez szükséges ezek megléte. Jó hír: nem kell lemondanod róluk.

Az alábbi kódrészletek olvasásához legalább az alap javascript szintaktikának ismerősnek kell lennie, és az ezt leíró kifejezéseknek.

Az egyik legerősebb megoldás a javascriptben a closure és a belső funkciók. Ez azt jelenti, hogy még ha egy változó látókörét elhagyjuk is, a változó értéke megmarad, amíg még hivatkozunk rá valahol.

Nézzünk egy példát:

Ha készítünk egy objektumot két tulajdonsággal és egy metódussal, mi lesz az elérhetőségük?

var ElsoObj = {
    ParamEgy: 1,
    ParamKetto: 'kettő',
    FunkcEgy: function () {
      return ParamEgy+ ParamKetto;
    }
};
alert(ElsoObj.ParamEgy);
alert(ElsoObj.ParamKetto);
alert(ElsoObj.FunkcEgy());

A kód három popup ablakot dob fel az

  • 1
  • kettő
  • 1kettő

értékekkel, ebben a sorrendben. Eszerint minden tulajdonság és metódus nyilvánosan elérhető az objektumban.

De szeretnénk, ha lennének védetteink is. A megoldás kulcsa a fent említett closure-ben rejlik. Mivel a javascript-ben van funkció-szintű látókör, mi történik, ha bezárjuk mindezt egy funkcióba?

var ElsoObj = function () {
    var ParamEgy = 1,
    ParamKetto = 'kettő',
    FunkcEgy = function () {
      return ParamEgy + ParamKetto;
    };
};

A kód futtatása után a visszatérési értékek a következők:

  • undefined
  • undefined
  • ElsoObj.FunkcEgy is not a function

Viszont ElsoObj egy funkció két lokális változóval és egy belső funkcióval, amit sosem hívtunk meg.

Szóval, próbáljunk meg egy kisebb változtatást, hívjuk meg az előbbi funkciót, és a visszatérési értékét adjuk az ElsoObj-nak.

var ElsoObj = (function () {
    var ParamEgy = 1,
    ParamKetto = 'kettő',
    FunkcEgy = function () {
        return ParamEgy + ParamKetto;
    };
}());

A teljes funkcióhívás körül lévő zárójelek arra utalnak, hogy ez az értékadás nem a funkciót adja értékül, hanem az azonnali meghívásának a visszatérési értékét.

Az eredményeink száma lecsökken egyre:

  • ElsoObj is undefined

Ennek az oka, hogy amikor egy funkciónak nincs meghatározott visszatérési értéke, az a beépített undefined értékkel tér vissza. A belső funkciónak van ugyan visszatérési értéke, de azt nem hívtuk meg, és még akkor sem lenne ugyanaz a külső funkció visszatérési értéke. Adjunk meg egyet:

var ElsoObj = (function () {
    var ParamEgy = 1,
    ParamKetto = 'kettő',
    FunkcEgy = function () {
        return ParamKetto + ParamKetto;
    };
    return FunkcEgy;
}());

Most már van visszatérési értékünk, és a paraméterek olvasási kísérlete a most elvárható eredményt hozza:

  • undefined
  • undefined

De a funkcióhívás még mindig hibás:

  • ElsoObj.FunkcEgy is not a function

Ha közelebbről megnézzük a kódot, hamar rájöhetünk az indokra:

    return FunkcEgy;

A visszatérési értékadásnál nem objektumot adtunk át az ElsoObj-nak, hanem a belső funkcióra való hivatkozást. Így, ha közvetlenül az ElsoObj()-t hívjuk, az első példához hasonló eredményt kapunk:

  • 1kettő

Szóval a negyedik kód két védett változót tartalmaz ParamEgy és ParamKetto, amit az ElsoObj-ban tárolt funkcióval érhetünk el. Ez az eredmény már felérhet a lap elején feltett kritériumoknak, az egyetlen probléma, ha el szeretnénk érni az értékeket külön-külön és összefűzve is.

Majdnem minden objektumnak számít javascript-ben, így lehet objektum egy visszatérési érték is. Ebben az esetben köthetünk több különböző funkciót is egy változóhoz, ami megoldhatja ezt a feladatot nekünk.

var ElsoObj = (function () {
    var ParamEgy = 1,
    ParamKetto = 'kettő',
    FunkcEgy = function () {
        return ParamEgy + ParamKetto;
    };
    return {
        callFunkcEgy: FunkcEgy,
        getParamKetto: function () {
            return ParamEgy;
        },
        getParamKetto: function () {
            return ParamKetto;
        }
    };
}());

Sajnálatos módon a popup ablakok undefined-et és hibát adnak vissza. Ez azért van, mert a visszaadott objektumban nincs tulajdonság, van viszont három funkció, ezek mindegyike különbözik a FunkcEgy-től. Az új hívások az értékek meghatározására, a belső funkció hívására és így egyben az utolsó kódrészletünk ezzel:

<script type="text/javascript">
var ElsoObj = (function () {
    var ParamEgy = 1,
    ParamKetto = 'kettő',
    FunkcEgy = function () {
        return ParamEgy + ParamKetto;
    };
    return {
        callFunkcEgy: FunkcEgy,
        getParamEgy: function () {
            return ParamEgy;
        },
        getParamKetto: function () {
            return ParamKetto;
        }
    };
}());
alert(ElsoObj.getParamEgy());
alert(ElsoObj.getParamKetto());
alert(ElsoObj.callFunkcEgy());
</script>

Sikerrel készítettünk egy javascript objektumot védett tulajdonságokkal és funkcióval, és hoztunk létre ezeket elérő felületet is.

A védett funkciókból is elérhető nyilvános tulajdonságok létrehozása egy fokkal nehezebb, de természetesen ez sem lehetetlen.

Védett funkciókból is elérhető nyilvános tulajdonságok

Építsünk egy alap objektumot védett és nyilvános tulajdonságokkal:

<script type="text/javascript">
var MasodikObj = (function () {
    // védett tulajdonságok
    var PrivEgy = 'pr1',
        PrivKetto = 'pr2';
    return {
        // nyilvános tulajdonságok
        NyilvEgy = 'pu1',
        NyilvKetto = 'pu2'
    };
}());
</script>

Egészítsük ki funkciókkal is:

<script type="text/javascript">
var MasodikObj = (function () {
    var PrivEgy = 'pr1',
        PrivKetto = 'pr2',
        // védett tulajdonságok
        PrFunkcEgy = function () {
            return PrivEgy + PrivKetto;
        };
    return {
        NyilvEgy: 'ny1',
        NyilvKetto: 'ny2',
        // nyilvános tulajdonságok
        PubFunkcEgy: function () {
            return PrivEgy + PrivKetto;
        },
        // átjáró a belső funkcióhoz
        NyilvPrivFunkc: PrFunkcEgy
    };
}());
</script>

Az objektumnak van két nyilvános tulajdonsága, két védett tulajdonsága, egy nyilvános funkciója és egy védett, nyilvános felülettel, hogy leellenőrizhessük mit csinál. Ezekkel már találkoztunk az első részben, most pedig kísérletezzünk.

Mi történik, ha nyilvános tulajdonságokat próbálunk elérni a belső funkcióból, amik a visszatérő objektumban vannak? A próbaképp kiadott utasítás: alert(MasodikObj.NyilvPrivFunc());

<script type="text/javascript">
var MasodikObj = (function () {
    var PrivEgy = 'pr1',
        PrivKetto = 'pr2',
        PrFunkcEgy = function () {
            // próbáljuk NyilvEgy vagy NyilvKetto-t
            return NyilvEgy + NyilvKetto;
        };
    return {
        NyilvEgy: 'ny1',
        NyilvKetto: 'ny2',
        PubFunkcEgy: function () {
            return PrivEgy + PrivKetto;
        },
        NyilvPrivFunkc: PrFunkcEgy
    };
}());
// eredmények ellenőrzése
alert(MasodikObj.NyilvPrivFunkc());
</script>

Ezzel a kóddal egy szép hibaüzenethez jutunk:

  • NyilvEgy is undefined

Annak ellenére, hogy javascript-ben funkció-látókör van, az objektumok önállóak, és minden belső funkció saját lokális hatókört nyit magának. Így nincs lehetőség a futásidőben létrehozott objektum tulajdonságaihoz hozzáférni.

Mivel tudjuk, hogy a létrehozott objektum a MasodikObj lesz, ezen keresztül elérhetjük a tulajdonságait, a 6. sor így:

            return MasodikObj.NyilvEgy + MasodikObj.NyilvKetto;

Az eredmény, ahogy lennie kell: ny1ny2. Ezzel elértük, amit akartunk: nyilvános tulajdonságok elérése egy belső funkcióban. Egy baj van csak, nem tudhatjuk minden esetben mi lesz a neve a végső objektumnak, ahogy abban sem lehetünk biztosak, hogy mindig ugyanaz lesz. Az is előfordulhat, hogy két egyforma objektumra lesz szükségünk. Más megoldást kell keresnünk…

Minden változó, amit a külső funkcióban deklarálunk, elérhető minden belső funkcióban, valamint használható visszatérési értékként. Épp ezért cseréljük le a futásidőben létrehozott objektumot egy előre definiálttal:

<script type="text/javascript">
var MasodikObj = (function () {
    var PrivEgy = 'pr1',
        PrivKetto = 'pr2',
        PrFunkcEgy = function () {
            // itt elérjük ReturnObject tulajdonságait,
            // mivel bent vannak a látókörben
            return ReturnObject.NyilvEgy + ReturnObject.NyilvKetto;
        },
        EredmenyObject = {
            NyilvEgy: 'ny1',
            NyilvKetto: 'ny2',
            PubFunkcEgy: function () {
                return PrivEgy + PrivKetto;
            },
            NyilvPrivFunkc: PrFunkcEgy
        };
    return EredmenyObject;
}());
alert(MasodikObj.NyilvPrivFunkc());
</script>

Összefoglalás:

Amit ebben a rövid leckében elértünk: vannak nyilvános és védett tulajdonságaink, mint ahogy védett és nyilvános funkcióink, és minkét funkciótípusból hozzáférünk mindkét típusú tulajdonsághoz (a megfelelő címzéssel).