Mint a szülő programozási nyelvben, javascript-ben is használhatóak változók. Ezek a nevesített memóriaterületek tartalmazzák a program futása során használt értékeket.
A hatékony használatukhoz azonban szükség van a bevezetésük módjának valamint a hatókörüknek a pontos ismeretére.

Változók létrehozása

A Javascript egy lazán típusos nyelv. Ez annyit jelent, hogy a változók a program futása során egymás után több különböző típusú értéket is felvehetnek. Ennek a tulajdonságnak adott esetben lehet hátránya is, hiszen az értelmező nem ad hibaüzenetet, ha egy eddig számot tartalmazó változóhoz szöveget rendelünk hozzá.
Egy változó bevezetése a var kulcsszóval történik, bár a hatókör értelmezéséből adódóan az sem okoz futási hibát, ha a kulcsszó elmarad.

var peldaValtozo;

Ez egy kezdőérték nélküli változó bevezetését jelenti az éppen aktuális hatókörbe. Lehetőség van a változónak kezdőértéket is adni, ezt a deklaráció sorában történő értékadással tehetjük meg.

var peldaValtozo = 10.3;

Ebben az esetben a változónk egy lebegőpontos számot tárol. Az értékadás jobb oldalán bármi állhat, amit értékként lehet értelmezni Javascriptben. Így mindez lehet: szám, szöveg, boolean, objektum, null vagy undefined (részletesen róluk).
Ennek értelmében mindkét alábbi definíció helyes, és egyenértékű egymással:

var peldaFunkcio = function (parameter) { utasitasok; ... }
function peldaFunkcio (parameter) { utasitasok; ... }

Láthatóság

Ezzel el is érkeztünk a láthatósági kérdésig. Létrehoztunk egy változót, de hol használhatjuk fel?
A javascript írásmódja alapján, valamint a szülő c szabályai szerint block-szintű hatókört kellene tapasztaljunk, viszont ez nem fedi a valóságot. A javascript egyetlen hatókört értelmez, ez pedig a funkció-alapú hatókör. Minden változó az őt befoglaló funkcióban értelmezett, azon kívül nem hozzáférhető, azon belül viszont mindenhol. Ez sok érdekes lehetőséget rejt magában.
Kezdjük az alapesettel:

function funkcio1 () {
    var valtozo1 = 10.3;
    alert (valtozo1);
}
funkcio1(); /* 10.3 */
alert(valtozo1); /* undefined */

A valtozo értéke a funkción belül elérhető és használható, az ezen kívül helyezett alert egy undefined értéket fog kiírni.
Nézzük meg mi történik, ha már a funkciónk megadása előtt is létezett egy ugyanilyen nevű változó:

var valtozo1 = "alapérték";
function funkcio1 () {
    var valtozo1 = 10.3;
    alert (valtozo1);
}
funkcio1(); /* 10.3 */
alert(valtozo1); /* alapérték */

Ebben az esetben a meghívott funkción belül a lokális változó saját hatókörben felülbírálja/eltakarja a funkción kívül létrehozott változót.
Itt rögtön elkövethetjük az első programozói hibát: lehagyjuk a var kulcsszót a deklarációról.
Ebben az esetben ugyanis a funkción belül hivatkozott változó már nem takarja el, hanem felülírja a kívül deklarált változó értékét.

var valtozo1 = "alapérték";
function funkcio1 () {
    valtozo1 = 10.3;
    alert (valtozo1);
}
funkcio1(); /* 10.3 */
alert(valtozo1); /* 10.3 */

Mi történik akkor, ha a funkciókon kívül nincs deklarálva egy változó, és funkción belül is csak értéket adok neki?
Minden nem deklarált változót az adott hatókörből kiindulva az egyre tágabbak felé haladva keres az értelmező. Ha sehol nem találja, akkor létrehozza azt a globális névtérben, és ott módosítja az értékét is.
Itt vetődik fel a megszokásból létrehozott ciklusváltozók problémája:

function funkcio1 (szoveg) {
    for (i = 0; i < szoveg.length; i += 1) {
        alert(szoveg[i]);
    }
}
function funkcio2 () {
    var tomb1 = ['egy', 'ketto', 'harom'];
    for (i = 0; i < tomb1.length; i += 1) {
        funkcio1(tomb1[i]);
    }
}
funkcio2();

Nem túl életszagú példa, viszont egy sokak által nehezen felismerhető programozási hibát rejt magában. A várt futás eredményeként a következő betűkkel kell hogy jelentkezzen a Javascript figyelmeztető ablaka:
e, g, y, k, e, t, t, o, h, a, r, o, m.
Ennek ellenére a következő fog történni:
A funkcio2 második sorában az értelmező létrehoz egy i nevű globális változót, aminek a 0 kezdőértéket adja, majd meghívja a funkcio1-et. Ebben szintén van egy nem-lokális hivatkozás i-re, de a szabályoknak megfelelően az értelmező a globális i-t használja. Emiatt azonban a tömb második elemét sosem fogja feldolgozni, mivel a funkcio2-n belüli for ciklus már elérte a kilépési feltételt: a globális i már nem kisebb, mint 3.
Az értelmező nem ad hibát, mivel a teljes kód szintaktikailag helyes, és a hibát is általában a funkcio1-en belül keresnénk, holott ennél összetettebb jelenségről van szó. Éppen ezért jó lehet megszokni kódíráshoz a c-ből – és hasonló nyelvekből – már ismert definíciós szabályokat:
Minden funkció elején definiáljuk a funkció lokális változóit, illetve utaljunk legalább megjegyzés szintjén a külsőbb szintekről hivatkozottakra, hogy a nem kívánt elfedéseket és felülírásokat elkerülhessük.
Ez alapján egy lokális és globális változókat egyaránt használó funkció definíciója a következőképp alakul:

var global1 = null;
var global2 = 17;
var global3;
function funkcio1 () {
    /* módosítja a global2-t */
    var lokal1;
    var lokal2 = "Ez egy lokális változó értéke";
    ...
    [ utasításblokk ]
    ...
}

Amennyiben tudjuk, hogy a ciklusváltozókat sehol máshol nem kívánjuk használni, mint a ciklusok fejlécében, azt nem kell mindenképpen a funkció elején definiálni, hanem elég a ciklusfejlécben megadni a változó előtt a var kulcsszót. Ez abban az esetben sem ad hibát, amennyiben egy funkción belül kétszer definiáljuk ugyanazt a változót, mivel a második definíció esetében is a már korábban létrehozott változót használhatjuk.

function funkcio1 () {
    ...
    for (var i = 0; i < 100; i += 1) {
        ...
        [ ciklusmag ]
        ...
    }
    ...
    for (var i = 0; i < 100; i += 1) {
        ...
        [ ciklusmag ]
        ...
    }
    ...
}

Amennyiben minden ciklusban használjuk a var kulcsszót, és adunk kezdőértéket is egyben, sok fejfájásos hibakereséstől tudjuk megóvni magunkat, és adott esetben másokat is.