Википедия:

Переменные в JavaScript

Про переменные в JavaScript написано мало. В основном описание арифметических операций да работа со строками. Очень часто авторы справочников и руководств пишут откровенную чушь. Печальную картину мракобесия дополняет одна «мутная тема» которую авторы осторожно обходят стороной. Использовать ли при декларации переменной ключевое слово var или нет, да и зачем оно вообще?

Как известно, самая полная информация, без фантазий и домыслов, содержится в первоисточниках. Первоисточником информации по JavaScript служит документация компаний:

Про переменные, в частности про использование var, «отцы» JavaScript сообщают следующее:

JavaScript is a loosely typed language. That means you do not have to specify the data type of a variable when you declare it, and data types are converted automatically as needed during script execution. var
Declares a variable, optionally initializing it to a value. Using var outside a function is optional; you can declare a variable by simply assigning it a value. However, it is good style to use var, and it is necessary in functions in the following situations:

  1. If a global variable of the same name exists.
  2. If recursive or multiple functions use variables with the same name.

Сказано на самом деле три очень важных вещи. JavaScript — слабо типизированный язык, тип переменной определяется во время исполнения скрипта.

 Использование var при декларации переменных вне функции — необязательно.

Использование var необходимо при декларации локальных переменных в функции, в тех случаях, когда существует глобальная переменная с таким же именем, в рекурсивных функциях, если переменная с указанным именем используется в нескольких функциях.

Почему это так, официальная документация умалчивает, однако ситуацию проясняет MSDN, расписывая все более подробно, в отличие от…

If you do not initialize your variable in the var statement, it automatically takes on the JScript value undefined. Although it is unsafe to do so, it is legal JScript syntax to omit the var keyword from your declaration statement. When you do, the JScript interpreter gives the variable global scope visibility. When you declare a variable at the procedure level though, you do not want it to be visible at the global scope; in this case, you must use the var keyword in your variable declaration.

Если кратко, переменная объявленная без ключевого слова var трактуется интерпретатором как глобальная, вне зависимости от того, где она была объявлена.

Переменные и объекты в JavaScript

В языках программирования переменная характеризуется именем, типом и областью видимости1. Конкретно в JavaScript имя переменной — последовательность символов, начинающаяся с буквы либо символа подчеркивания.

A JavaScript identifier, or name, must start with a letter or underscore ("_"); subsequent characters can also be digits (0-9). Because JavaScript is case sensitive, letters include the characters "A" through "Z" (uppercase) and the characters "a" through "z" (lowercase). Some examples of legal names are Number_hits, temp99, and _name.

Как уже упоминалось выше, JavaScript язык слабо-типизированный. Все переменные являются объектами. Именно объектами, а не строками или числами, как пишут в своих руководствах некоторые безграмотные мудаки.

Для работы с простейшими типами данных предусмотрено семь фундаментальных типов объектов.
Number, Boolean, String — числа, булевы значения и строки.
Function — объект представляющий JavaScript код, транслирующийся в функцию. Про использование переменных такого типа можно прочитать в главе посвященной обработке клавиатурных событий.
Array и Date — объекты для работы с коллекциями и датами.
Math — библиотека математических функций. Все вышеперечисленные объекты имеют методы:

  1. eval
  2. toString
  3. valueOf

Тип любого объекта можно узнать с помощью оператора typeof. Не инициализированный объект имеет значение undefined.

Note that the main difference between null and undefined in JScript is that null behaves like the number 0, while undefined behaves like the special value NaN (Not a Number). A null value and an undefined value will always compare to be equal.

Область видимости — блок кода в котором переменная доступна для использования. Как правило, это блок кода заключенный в фигурные скобки {…} внутри которого была определена переменная.

Область видимости переменных в JavaScript

В отличие от C++ или Java, в JavaScript фигурные скобки {…} не определяют нового блока. Другими словами, переменная определенная внутри блока {…} расположенного в документе, является такой же глобальной переменной, как и переменная, объявленная непосредственно в документе.

Переменная, определенная внутри блока {…} расположенного в функции, является такой же локальной переменной, как и переменная объявленная непосредственно в функции. В этом можно убедиться написав простенький скрипт, про это же говорит и MSDN. Отцы молчат.

Languages such as C++ also have "block scope." Here, any set of braces "{}" defines a new scope. JScript does not support block scopes.

Так как все скрипты импортируются в одну страницу и модулей, как таковых, нет, то область видимости переменной в JavaScript ограничена либо документом (html-страницей, содержащей скрипт) либо функцией. Соответственно, переменные объявленные в документе называются глобальными, переменные объявленные внутри функций — локальными. Время жизни всех глобальных переменных — до следующего обновления страницы или закрытия окна.

Использовать глобальные переменные непосредственно в коде страницы можно только после декларации этой переменной. В функциях глобальные переменные можно использовать вне зависимости от того, были ли они объявлены до функции или после. Впрочем, это может зависеть от интерпретатора.
Пример, иллюстрирующий вышесказанное.

<script language = "javascript">
<!--

var first = 0;
alert("Значение переменной first :" + first);
alert("Значение переменной second :" + second);
{
var second = 1;
alert("Значение переменной second :" + second);
second = 2;
}
alert("Значение переменной second :" + second);
//-->
</script>

Пример откроется в новом окне.

Глобальные переменные в JavaScript

Все глобальные переменные являются новыми свойствами объекта window. Фактически, при объявлении новой переменной у объекта window создается новое свойство имя которого совпадает с именем переменной. Скажем, var count = 0; создает свойство count.

Доступ к глобальным переменным в документе осуществляется неявно, просто по имени либо, так как все глобальные переменные являются свойствами объекта window, с явным указанием window.переменная.
Последний способ используется для явной спецификации доступа к глобальной переменной в том случае, когда имена локальной и глобальной переменных совпадают. В остальных случаях такой метод будет только загромождать код.

Так как область видимости глобальных переменных — документ, то доступны они из любой функции, находящейся в этом документе.

var nCount = 0;
function jsVariables()
{
var nCount = 10;
alert("Значение локальной переменной nCount :" + nCount);
alert("Значение глобальной переменной nCount :" + window.nCount);
}


Для доступа к глобальным переменным другого документа требуется указывать имя окна содержащего документ, к глобальной переменной которого требуется доступ.

You can access global variables declared in one window or frame from another window or frame by specifying the window or frame name. For example, if a variable called phoneNumber is declared in a FRAMESET document, you can refer to this variable from a child frame as parent.phoneNumber.

Использование var при декларации глобальных переменных

Так как в пространстве имен с одним именем может существовать только одна переменная, то использование var при декларации глобальных переменных не обязательно. Если объекта с существующим именем нет — он будет создан, если есть — его значение будет изменено.
Будет ли создан новый объект в следующем случае,
var i = 0;
var i = 2;
вероятно, зависит от реализации JavaScript интерпретатора.

Использование var при декларации локальных переменных

Каждая функция определяет ограниченное ее телом локальное пространство имен. Таким образом, из функции доступны оба-два пространства имен — глобальное и локальное. А так как имя переменной идентифицирует переменную в рамках пространства имен, то в каждом из них можно объявить переменные с одинаковыми именами которые приэтом будут различны.

Поэтому, предполагаемая декларация локальной переменной count = 10 (без использования var), приведет к декларации глобальной переменной либо, если глобальная переменная с таким именем уже существует, к перезаписи ее значения.

var first = 10;
var second = 10;

function jsLocalVariables()
{
first = 0;
alert("Значение локальной переменной first :" + first);
alert("Значение глобальной переменной first :" + window.first);

var second = 0;
alert("Значение локальной переменной second :" + second);
alert("Значение глобальной переменной second :" + window.second);
{
var second = 17;
alert("Значение локальной переменной second блока :" + second);
}
alert("Значение локальной переменной second :" + second);
}


Два несколько надуманных примера, иллюстрирующие возможные проблемы.
Декларация локальных переменных с одинаковым именем без использования var в нескольких функциях.

function jsMultiFunctions()
{
i = 0;
var count = calculate(10);

for ( ;i < 5; i++)
count++;
//предполагаемое значение переменной count 15.
alert("Значение переменной count:" + count);
}

function calculate(nLast)
{
var count = 0;
for (i = 0; i < nLast; i++)
count++;
return count;
}


В рекурсивных функциях

function jsRecursiveFunctions()
{
var nResult = f(2, 2);
//предполагаемое значение переменной nResult 6 (2*2 + 2*1).
alert("Значение переменной nResult:" + nResult);
}

function f(step, v)
{
if (step == 0)
return 0;

nValue = step * v;

var nF = f(step - 1, v);
nValue += nF;
return nValue;
}



1) В С++, например, переменная помимо этого может характеризоваться квалификатором доступа const или volatile. Но это технические детали, общих характеристик все-таки три. Да и к JavaScript это не имеет никакого отношения.