Na początek zagadka: jakie komunikaty wyświetli poniższy kod?
1 2 3 4 5 6 7 8 9 |
var x = 5, y = true; (function () { alert(x); if (y) { var x = 10; } })(); |
Odpowiedź brzmi, oczywiście: undefined!
W przeciwieństwie do jezyków takich jak C czy C#, nie każdy blok kodu definiuje zakres zmiennej, a jedynie funkcja. Nie ma przy tym znaczenia, w którym miejscu funkcji zmienną zadeklarujemy – będzie ona dostępna w całej funkcji, także przed deklaracją. Dlatego alert(x) nie zobaczy zmiennej globalnej, tylko lokalną. I zobaczy undefined dlatego, że co prawda zmienna jest już zdefiniowana, ale przypisanie do niej wartości ma miejsce później.
Powyższy kod będzie więc równoważny z takim:
1 2 3 4 5 6 7 8 9 10 |
var x = 5, y = true; (function () { var x; alert(x); if (y) { x = 10; } })(); |
A zatem – można powiezieć, że deklaracje zmiennych są jakby “wyciągane” (ang hoisted) na początek funkcji.
Ot, jedno z wielu dziwactw JavaScriptu.
Jaki z tego morał? Dobrą praktyką jest deklarowanie wszystkich zmiennych w jednej instrukcji var na samym początku funkcji. Taką też regułę posiada JSLint (i jego fork, JSHint), narzędzie sprawdzające styl kodu, którego używać powinien każdy programista JS.