Лекция
Привет, сегодня поговорим про глобальный объект, обещаю рассказать все что знаю. Для того чтобы лучше понимать что такое глобальный объект , настоятельно рекомендую прочитать все из категории Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend).
Механизм работы функций и переменных в JavaScript очень отличается от большинства языков.
Чтобы его понять, мы в этой главе рассмотрим переменные и функции в глобальной области. А в следующей — пойдем дальше.
Глобальными называют переменные и функции, которые не находятся внутри какой-то функции. То есть, иными словами, если переменная или функция не находятся внутри конструкции function, то они — «глобальные».
В JavaScript все глобальные переменные и функции являются свойствами специального объекта, который называется «глобальный объект» (global object).
В браузере этот объект явно доступен под именем window. Объект window одновременно является глобальным объектом и содержит ряд свойств и методов для работы с окном браузера, но нас здесь интересует только его роль как глобального объекта.
В других окружениях, например Node.JS, глобальный объект может быть недоступен в явном виде, но суть происходящего от этого не изменяется, поэтому далее для обозначения глобального объекта мы будем использовать "window".
Присваивая или читая глобальную переменную, мы, фактически, работаем со свойствамиwindow.
Например:
1 |
var a = 5; // объявление var создает свойство window.a |
2 |
alert(window.a); // 5 |
Создать переменную можно и явным присваиванием в window:
1 |
window.a = 5; |
2 |
alert(a); // 5 |
Выполнение скрипта происходит в две фазы:
Во время инициализации скрипт сканируется на предмет объявления функций вида Function Declaration, а затем — на предмет объявления переменных var. Каждое такое объявление добавляется в window.
Функции, объявленные как Function Declaration, создаются сразу работающими, а переменные — равными undefined.
Присваивание (=) значений переменных происходит на второй фазе, когда поток выполнения доходит до соответствующей строчки кода.
В начале кода ниже указано содержание глобального объекта на момент окончания инициализации:
1 |
// По окончании инициализации, до выполнения кода: |
2 |
// window = { f: function, a: undefined, g: undefined } |
3 |
4 |
var a = 5; // при инициализации дает: window.a=undefined |
5 |
6 |
function f(arg) { /*...*/ } // при инициализации дает: window.f = function |
7 |
8 |
var g = function(arg) { /*...*/ }; // при инициализации дает: window.g = undefined |
Кстати, тот факт, что к началу выполнения кода переменные и функции уже содержатся в window, можно легко проверить:
1 |
alert("a" in window); // true, т.к. есть свойство window.a |
2 |
alert(a); // равно undefined, присваивание будет выполнено далее |
3 |
alert(f); // function ..., готовая к выполнению функция |
4 |
alert(g); // undefined, т.к. это переменная, а не Function Declaration |
5 |
6 |
var a = 5; |
7 |
function f() { /*...*/ } |
8 |
var g = function() { /*...*/ }; |
В старом стандарте JavaScript переменную можно было создать и без объявленияvar:
1 |
a = 5; |
2 |
3 |
alert(a); // 5 |
Такое присвоение, как и var a = 5, создает свойство window.a = 5. Отличие отvar a = 5 — в том, что переменная будет создана не на этапе входа в область видимости, а в момент присвоения.
Сравните два кода ниже.
Первый выведет undefined, так как переменная была добавлена в window на фазе инициализации:
1 |
alert(a); // undefined |
2 |
3 |
var a = 5; |
Второй код выведет ошибку, так как переменной еще не существует:
1 |
alert(a); // error, a is not defined |
2 |
3 |
a = 5; |
Вообще, рекомендуется всегда объявлять переменные через var.
В современном стандарте присваивание без var вызовет ошибку:
1 |
'use strict'; |
2 |
a = 5; // error, a is not defined |
for, if... не влияют на видимость переменныхФигурные скобки, которые используются в for, while, if, в отличие от объявлений функции, имеют «декоративный» характер.
В JavaScript нет разницы между объявлением вне блока:
1 |
var i; |
2 |
{ |
3 |
i = 5; |
4 |
} |
1 |
i = 5; |
2 |
{ |
3 |
var i; |
4 |
} |
Также нет разницы между объявлением в цикле и вне его:
1 |
for (var i=0; i<5; i++) { } |
1 |
var i; |
2 |
for (i=0; i<5; i++) { } |
В обоих случаях переменная будет создана до выполнения цикла, на стадии инициализации, и ее значение будет сохранено после окончания цикла.
Объявлений var может быть сколько угодно:
1 |
var i = 10; |
2 |
3 |
for (var i=0; i<20; i++) { |
4 |
... |
5 |
} |
6 |
7 |
var i = 5; |
Все var будут обработаны один раз, на фазе инициализации.
На фазе исполнения объявления var будут проигнорированы: они уже были обработаны. Об этом говорит сайт https://intellect.icu . Зато будут выполнены присваивания.
window в IE8-В старых IE есть две забавные ошибки при работе с переменными в window:
id элемента, приведет к ошибке:
1 |
<div id="a">...</div> |
2 |
<script> |
3 |
a = 5; // ошибка в IE<9! Правильно будет "var a = 5" |
4 |
alert(a); // никогда не сработает |
5 |
</script> |
А если сделать через var, то все будет хорошо.
Это была реклама того, что надо везде ставить var.
window. Следующий код «умрет» в IE<9:
1 |
<script> |
2 |
// рекурсия через функцию, явно записанную в window |
3 |
window.recurse = function(times) { |
4 |
if (times !== 0) recurse(times-1); |
5 |
} |
6 |
7 |
recurse(13); |
8 |
</script> |
Проблема здесь возникает из-за того, что функция напрямую присвоена вwindow.recurse = .... Ее не будет при обычном объявлении функции.
Этот пример выдаст ошибку только в настоящем IE8! Не IE9 в режиме эмуляции. Вообще, режим эмуляции позволяет отлавливать где-то 95% несовместимостей и проблем, а для оставшихся 5% вам нужен будет настоящий IE8 в виртуальной машине.
В результате инициализации, к началу выполнения кода:
Function Declaration, создаются полностью и готовы к использованию.undefined. Присваивания выполнятся позже, когда выполнение дойдет до них.
К сожалению, в одной статье не просто дать все знания про глобальный объект. Но я - старался. Если ты проявишь интерес к раскрытию подробностей,я обязательно напишу продолжение! Надеюсь, что теперь ты понял что такое глобальный объект и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)
Комментарии