В следующем фрагменте переменные i, j и к объявляются в разных местах, но все они имеют одну и ту же область видимости - все три переменные доступны из любого места в теле функции:
function test(o) {
var і = 0; // і определена в теле всей функции
if (typeof о == "object") {
var j = 0; // j определена везде, не только в блоке
for(var k=0; k < 10; k++) { // к определена везде, не только в цикле
console.log(k); // выведет числа от 0 до 9
}
console.log(k); // к по-прежнему определена: выведет 10
}
console.log(j); // j определена, но может быть неинициализирована
}
Область видимости функции в языке JavaScript подразумевает, что все переменные, объявленные внутри функции, видимы везде в теле функции. Самое интересное, что переменные оказываются видимыми еще до того, как будут объявлены. Эта особенность JavaScript неофициально называется подъемом: программный код JavaScript ведет себя так, как если бы все объявления переменных внутри функции (без присваивания инициализирующих значений) «поднимались» в начало функции. Рассмотрим следующий фрагмент:
var scope = "global";
function f() {
console.log(scope); // Выведет "undefined", а не "global"
var scope = "local"; // Инициализируется здесь, а определена везде
console.log(scope); // Выведет "local"
}
Можно было бы подумать, что первая инструкция внутри функции должна вывести слово «global», потому что инструкция var с объявлением локальной переменной еще не была выполнена. Однако вследствие действия правил области видимости функции выводится совсем другое значение. Локальная переменная определена во всем теле функции, а это означает, что глобальная переменная с тем же именем оказывается скрытой для всей функции. Хотя локальная переменная определена во всем теле функции, она остается неинициализированной до выполнения инструкции var. То есть функция выше эквивалентна реализации, приведенной ниже, в которой объявление переменной «поднято» в начало функции, а инициализация переменной выполняется там же, где и раньше:
function f() {
var scope; // Объявление локальной переменной в начале функции
console.log(scope); // Здесь она доступна, но имеет значение "undefined"
scope = "local"; // Здесь она инициализируется и получает свое значение
console.log(scope); // А здесь она имеет ожидаемое значение
}
В языках программирования, где поддерживаются области видимости блоков, рекомендуется объявлять переменные как можно ближе к тому месту, где они используются, а область видимости делать как можно более узкой. Поскольку в JavaScript не поддерживаются области видимости блоков, некоторые программисты стремятся объявлять все переменные в начале функции, а не рядом с местом, где они используются. Такой подход позволяет более точно отражать истинную область видимости переменных в программном коде.
3.10.2. Переменные как свойства
При объявлении глобальной переменной в JavaScript в действительности создается свойство глобального объекта (раздел 3.5). Если глобальная переменная объявляется с помощью инструкции var, создается ненастраиваемое свойство (раздел 6.7), т. е. свойство, которое невозможно удалить с помощью оператора delete. Как уже отмечалось выше, если не используется строгий режим и необъявленной переменной присваивается некоторое значение, интерпретатор JavaScript автоматически создает глобальную переменную. Переменные, созданные таким способом, становятся обычными, настраиваемыми свойствами глобального объекта и могут быть удалены:
var truevar = 1; // Правильно объявленная глобальная переменная, неудаляемая.
fakevar = 2; // Создается удаляемое свойство глобального объекта.
this.fakevar2 = 3; // То же самое.
delete truevar // => false: переменная не была удалена
delete fakevar // => true: переменная удалена
delete this.fakevar2 // => true: переменная удалена