A javascript egyik legnagyobb erőssége a bezárás (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.
Ennek a mondatnak a jobb megértéséhez tudnunk kell, hogy a javascript funkció-alapú látókörrel rendelkezik. Amikor egy változót deklarálunk egy funkción belül, az onnan kezdve a teljes funkción belül látható és elérhető, ahogy a blokkjain belül is.

Mivel egy funkció létrehozása nem más, mint egy változó létrehozása értékadással, egyszerűen hozhatunk létre belső funkciókat egy külsőben.

function kulso () {
    ...
    var belso = function () { // vagy egyszerűen: function belso () {
        ...
    }
    ...
};

Definíció alapján, ha létrehozunk egy változót a külső funkcióban, az elérhető lesz a belső funkciókban is. Az egyetlen kivétel, ha létrehozunk egy belső változót is ugyanazzal a névvel, mert az eltakarja/elfedi a külső változót.

function kulso () {
    var x = 10;
    alert(x);
    function belso () {
        // külső látókörből elérhető
        x = 20;
        alert(x);
    }
    belso();
    alert(x);
}

Ebben a példában a kulso() meghívása három figyelmeztető ablakot nyit fel a 10, 20, 20 értékekkel, ebben a sorrendben. Itt x nem helyi változó, hanem referencia a külső változóra. Ez azt jelenti, hogy amikor értéket adtunk x-nek a belső funkcióban, ugyanazt a változót használtuk, mint amit három sorral feljebb hoztunk létre.
De mi lesz a hatása, ha x-et helyi változónak hozzuk létre a var használatával?

function kulso () {
    var x = 10;
    alert(x);
    function belso () {
        // helyileg deklarált
        var x = 20;
        alert(x);
    }
    belso();
    alert(x);
}

Ebben az esetben a belső deklaráció eltakarja a külsőt, az már nem lesz elérhető, de a helyileg létrehozott x-et nyugodtan használhatjuk arra a célra, amire létrehoztuk. A három érték, amit most kapunk a kulso() hívásakor rendre: 10, 20 és 10.

Hasznos szokás, ha a változók deklarációja előtt megjegyzésben megemlítjük a külső látókörből használni kívánt változókat, hogy ne takarjuk el őket helyi deklarációval.

Hogyan érhetjük el, hogy egy változó hatóköréből kilépjünk, és maradjon rá érvényes hivatkozás?
A legegyszerűbb ha egy objektumot nem az objektum-literál segítségével hozunk létre, hanem egy függvény visszatérési értékeként:

var objektum1 = function () {
    var ertek = 0;
    return {
        megnovel: function (mennyivel) {
            if (typeof(mennyivel) === 'number') {
                ertek += mennyivel;
            } else {
                ertek += 1;
            }
        }
        mennyi: function () {
            return ertek;
        }
    };
}(); /* a függvényt azonnal meg is hívjuk,
    és így a visszatérési érték lesz az objektum értéke,
    és nem a névtelen funkció */

Mi is csinál pontosan a fenti kódrészlet?

  • Bevezetünk egy új változót objektum néven az aktuális hatókörbe (globális lesz).
  • Létrehozunk egy névtelen funkciót, amelynek egy lokális változója van ertek, és egy függvényeket tartalmazó objektumot ad vissza.
  • Ezt a funkciót rögtön végre is hajtjuk, és a visszatérési értékét – az objektumot – hozzárendeljük az objektum1 nevű változóhoz.

Ezzel elértük, hogy érvényes legyen az objektum.megnovel(), valamint az objektum.mennyi() funkciók hívása, de vajon mit fognak ezek csinálni, hiszen az ertek nevű változó látóköre megszűnt, amikor a névtelen funkció hívása befejeződött?
A Javascript változók hatókörének szabályai szerint egy funkció mindig hozzáfér az őt befoglaló látókör(ök) változóihoz, amennyiben nem fedi el őket.
Éppen ezért a megnovel és a mennyi belső funkciók is hozzáférnek az ertek névvel létrehozott változóhoz, és képesek módosítani is azt, annak ellenére, hogy az objektum.ertek hívással nem lehet elérni. Ez az a helyzet, amikor egy változó látóköre megszűnik ugyan, de érvényes hivatkozások maradnak a látókör egyes változóira.

Nem így neveztük eddig őket, de ezzel a technikával a privát és publikus változókat és funkciókat tudjuk definiálni, kihasználva a Javascript szabályainak rugalmasságát. Ezzel elérhetővé vált a más objektumorientált nyelvekből ismerős absztrakció lehetősége: egy objektum tulajdonságait csak a felületként meghatározott funkciók segítségével lehessen módosítani.