# Глобальный объект Механизм работы функций и переменных в JavaScript очень отличается от большинства языков. Чтобы его понять, мы в этой главе рассмотрим переменные и функции в глобальной области. А в следующей -- пойдём дальше. [cut] ## Глобальный объект *Глобальными* называют переменные и функции, которые не находятся внутри какой-то функции. То есть, иными словами, если переменная или функция не находятся внутри конструкции `function`, то они -- "глобальные". **В JavaScript все глобальные переменные и функции являются свойствами специального объекта, который называется *"глобальный объект"* (`global object`).** В браузере этот объект явно доступен под именем `window`. Объект `window` одновременно является глобальным объектом и содержит ряд свойств и методов для работы с окном браузера, но нас здесь интересует только его роль как глобального объекта. В других окружениях, например Node.JS, глобальный объект может быть недоступен в явном виде, но суть происходящего от этого не изменяется, поэтому далее для обозначения глобального объекта мы будем использовать `"window"`. **Присваивая или читая глобальную переменную, мы, фактически, работаем со свойствами `window`.** Например: ```js //+ run untrusted refresh var a = 5; // объявление var создаёт свойство window.a alert(window.a); // 5 ``` Создать переменную можно и явным присваиванием в `window`: ```js //+ run untrusted refresh window.a = 5; alert(a); // 5 ``` ## Порядок инициализации Выполнение скрипта происходит в две фазы:
  1. На первой фазе происходит инициализация, подготовка к запуску. Во время инициализации скрипт сканируется на предмет объявления функций вида [Function Declaration](/function-declaration-expression), а затем -- на предмет объявления переменных `var`. Каждое такое объявление добавляется в `window`. **Функции, объявленные как Function Declaration, создаются сразу работающими, а переменные -- равными `undefined`.**
  2. На второй фазе -- собственно, выполнение. Присваивание (`=`) значений переменных происходит на второй фазе, когда поток выполнения доходит до соответствующей строчки кода.
В начале кода ниже указано содержание глобального объекта на момент окончания инициализации: ```js // По окончании инициализации, до выполнения кода: *!* // window = { f: function, a: undefined, g: undefined } */!* var a = 5; // при инициализации даёт: window.a=undefined function f(arg) { /*...*/ } // при инициализации даёт: window.f = function var g = function(arg) { /*...*/ }; // при инициализации даёт: window.g = undefined ``` Кстати, тот факт, что к началу выполнения кода переменные и функции *уже* содержатся в `window`, можно легко проверить: ```js //+ run untrusted refresh alert("a" in window); // *!*true*/!*, т.к. есть свойство window.a alert(a); // равно *!*undefined*/!*, присваивание будет выполнено далее alert(f); // *!*function ...*/!*, готовая к выполнению функция alert(g); // *!*undefined*/!*, т.к. это переменная, а не Function Declaration var a = 5; function f() { /*...*/ } var g = function() { /*...*/ }; ``` [smart header="Присвоение переменной без объявления"] В старом стандарте JavaScript переменную можно было создать и без объявления `var`: ```js //+ run a = 5; alert(a); // 5 ``` Такое присвоение, как и `var a = 5`, создает свойство `window.a = 5`. Отличие от `var a = 5` -- в том, что переменная будет создана не на этапе входа в область видимости, а в момент присвоения. Сравните два кода ниже. Первый выведет `undefined`, так как переменная была добавлена в `window` на фазе инициализации: ```js //+ run untrusted refresh *!* alert(a); // undefined */!* var a = 5; ``` Второй код выведет ошибку, так как переменной ещё не существует: ```js //+ run untrusted refresh *!* alert(a); // error, a is not defined */!* a = 5; ``` **Вообще, рекомендуется всегда объявлять переменные через `var`.** В современном стандарте присваивание без `var` вызовет ошибку: ```js //+ run 'use strict'; a = 5; // error, a is not defined ``` [/smart] [smart header="Конструкции `for, if...` не влияют на видимость переменных"] Фигурные скобки, которые используются в `for, while, if`, в отличие от объявлений функции, имеют "декоративный" характер. В JavaScript нет разницы между объявлением вне блока: ```js *!*var*/!* i; { i = 5; } ``` ...И внутри него: ```js i = 5; { *!*var*/!* i; } ``` **Также нет разницы между объявлением в цикле и вне его:** ```js //+ run untrusted refresh for (*!*var*/!* i=0; i<5; i++) { } ``` Идентичный по функциональности код: ```js //+ run untrusted refresh *!*var i;*/!* for (i=0; i<5; i++) { } ``` В обоих случаях переменная будет создана до выполнения цикла, на стадии инициализации, и ее значение будет сохранено после окончания цикла. [/smart] [smart header="Не важно, где и сколько раз объявлена переменная"] Объявлений `var` может быть сколько угодно: ```js var i = 10; for (var i=0; i<20; i++) { ... } var i = 5; ``` **Все `var` будут обработаны один раз, на фазе инициализации.** На фазе исполнения объявления `var` будут проигнорированы: они уже были обработаны. Зато будут выполнены присваивания. [/smart] [warn header="Ошибки при работе с `window` в IE8-"] В старых IE есть две забавные ошибки при работе с переменными в `window`:
  1. Переопределение переменной, у которой такое же имя, как и `id` элемента, приведет к ошибке: ```html
    ...
    ``` А если сделать через `var`, то всё будет хорошо. Это была реклама того, что надо везде ставить `var`.
  2. Ошибка при рекурсии через функцию-свойство `window`. Следующий код "умрет" в IE<9: ```html ``` Проблема здесь возникает из-за того, что функция напрямую присвоена в `window.recurse = ...`. Ее не будет при обычном объявлении функции. **Этот пример выдаст ошибку только в настоящем IE8!** Не IE9 в режиме эмуляции. Вообще, режим эмуляции позволяет отлавливать где-то 95% несовместимостей и проблем, а для оставшихся 5% вам нужен будет настоящий IE8 в виртуальной машине.
[/warn] ## Итого В результате инициализации, к началу выполнения кода:
  1. Функции, объявленные как `Function Declaration`, создаются полностью и готовы к использованию.
  2. Переменные объявлены, но равны `undefined`. Присваивания выполнятся позже, когда выполнение дойдет до них.