3.10. Область видимости переменной
Область видимости (
<b>scope</b>
) переменной - это та часть программы, для которой эта переменная определена. Глобальная переменная имеет глобальную область видимости - она определена для всей JavaScript-программы. В то же время переменные, объявленные внутри функции, определены только в ее теле. Они называются локальными и имеют локальную область видимости. Параметры функций также считаются локальными переменными, определенными только в теле этой функции.
Внутри тела функции локальная переменная имеет преимущество перед глобальной переменной с тем же именем. Если объявить локальную переменную или параметр функции с тем же именем, что у глобальной переменной, то фактически глобальная переменная будет скрыта:
<b>var scope = "global"; // Объявление глобальной переменной</b>
<b>function checkscope() { </b>
<b> var scope = "local"; // Объявление локальной переменной с тем же именем </b>
<b> return scope; // Вернет локальное значение, а не глобальное</b>
<b>}</b>
<b>checkscope() // => "local"</b>
Объявляя переменные с глобальной областью видимости, инструкцию
<b>var</b>
можно опустить, но при объявлении локальных переменных всегда следует использовать инструкцию
<b>var</b>
. Посмотрите, что получается, если этого не сделать:
<b>scope = "global";// Объявление глобальной переменной, даже без var.</b>
<b>function checkscope2() { </b>
<b>scope = "local"; // Ой! Мы изменили глобальную переменную.</b>
<b>myscope = "local"; // Неявно объявляется новая глоб. переменная.</b>
<b>return [scope, myscope];// Вернуть два значения.</b>
<b>checkscope2() // => ["local", "local"]: имеется побочный эффект!</b>
<b>scope // => "local": глобальная переменная изменилась.</b>
<b>myscope // => "local": нарушен порядок в глобальном пространстве имен.</b>
Определения функций могут быть вложенными. Каждая функция имеет собственную локальную область видимости, поэтому может быть несколько вложенных уровней локальных областей видимости. Например:
<b>var scope = "global scope"; // Глобальная переменная</b>
<b>function checkscopeO {</b>
<b> var scope = "local scope”; // Локальная переменная </b>
<b> function nestedO {</b>
<b> var scope = "nested scope"; // Вложенная область видимости локальных переменных </b>
<b> return scope; // Вернет значение этой переменной scope</b>
<b> }</b>
<b> return nested();</b>
<b>}</b>
3.10.1. Область видимости функции и подъем
В некоторых С-подобных языках программирования каждый блок программного кода внутри фигурных скобок имеет свою собственную область видимости, а переменные, объявленные внутри этих блоков, невидимы за их пределами. Эта особенность называется областью видимости блока, но она не поддерживается в языке JavaScript. Вместо этого в JavaScript используется такое понятие, как область видимости функции: переменные, объявленные внутри функции, доступны внутри функции, где они объявлены, а также внутри всех функций, вложенных в эту функцию.
В следующем фрагменте переменные i, j и к объявляются в разных местах, но все они имеют одну и ту же область видимости - все три переменные доступны из любого места в теле функции:
<b>function test(o) { </b>
<b> var і = 0; // і определена в теле всей функции</b>
<b> if (typeof о == "object") {</b>
<b> var j = 0; // j определена везде, не только в блоке</b>
<b> for(var k=0; k < 10; k++) { // к определена везде, не только в цикле </b>
<b> console.log(k); // выведет числа от 0 до 9</b>
<b> }</b>
<b> console.log(k); // к по-прежнему определена: выведет 10</b>
<b> }</b>
<b> console.log(j); // j определена, но может быть неинициализирована</b>
<b>}</b>
Область видимости функции в языке JavaScript подразумевает, что все переменные, объявленные внутри функции, видимы везде в теле функции. Самое интересное, что переменные оказываются видимыми еще до того, как будут объявлены. Эта особенность JavaScript неофициально называется подъемом: программный код JavaScript ведет себя так, как если бы все объявления переменных внутри функции (без присваивания инициализирующих значений) «поднимались» в начало функции. Рассмотрим следующий фрагмент:
<b>var scope = "global";</b>
<b>function f() {</b>
<b> console.log(scope); // Выведет "undefined", а не "global"</b>
<b> var scope = "local"; // Инициализируется здесь, а определена везде</b>
<b> console.log(scope); // Выведет "local"</b>
<b>}</b>
Можно было бы подумать, что первая инструкция внутри функции должна вывести слово «global», потому что инструкция
<b>var</b>
с объявлением локальной переменной еще не была выполнена. Однако вследствие действия правил области видимости функции выводится совсем другое значение. Локальная переменная определена во всем теле функции, а это означает, что глобальная переменная с тем же именем оказывается скрытой для всей функции. Хотя локальная переменная определена во всем теле функции, она остается неинициализированной до выполнения инструкции
<b>var</b>
. То есть функция выше эквивалентна реализации, приведенной ниже, в которой объявление переменной «поднято» в начало функции, а инициализация переменной выполняется там же, где и раньше: