Для меня одним из самых проблемных мест Javascript было управление переменными. Излагаю простым русским языком.
Переменные в Javascript бывают глобальными и локальными. Глобальная переменная доступна везде, локальная — только в текущей области видимости.
Технически, глобальные переменные — всего лишь свойства объекта
Из этого следует, что глобальные переменные могут затирать свойства
При присвоении значения неопределенной локальной переменной используется или создается глобальная переменная.
Таким образом можно легко затереть лишнего. По-моему такое поведение абсолютно нелогично, но, что ж, это не самое странное место яваскрипта. В любом случае неявного определения переменных стоит избегать.
Явно объявлять переменные можно и нужно ключевым словом
Такая строка всегда создает новую локальную переменную. Если объявление происходит вне функций, то она будет глобальной, что вполне логично.
Как объявить глобальную переменную из функции? Как обратиться к глобальной переменной, если есть локальная с таким же именем? Очень просто — нужно обратиться к ней как к свойству
Меня всегда смущало то, что в Javascript можно определять функции внутри функций, а использовать их потом где угодно. Ну да, если посмотреть, точно то же самое можно делать в Ruby, и, наверное, во многих других языках тоже.
Переменные при этом передаются очень просто: если на момент определения функции переменная существовала, то она будет существовать и внутри функции. Откуда бы ее не вызывали.
Передача кода по старинке — строкой, которая прогоняется через
Поскольку объекты в Javascript — это тоже типа функции, то свойство объекта определяется точно так же, как и переменная.
А еще в Javascript область видимости переменной ограничивается только функциями, а не блоками типа
А что
Отдельно замечу, что при оборачивании какой-то поведенческой логики в объект надо помнить, что в создаваемых DOM-событиях значение this самого объекта теряется.
Области видимости переменных
Переменные в Javascript бывают глобальными и локальными. Глобальная переменная доступна везде, локальная — только в текущей области видимости.
Технически, глобальные переменные — всего лишь свойства объекта
window
, поскольку весь код выполняется в его контексте.<script> alert(location); // сообщит window.location </script>
Из этого следует, что глобальные переменные могут затирать свойства
window
(я уже молчу о том, что они зло, нарушают инкапсуляцию и все такое).Объявление переменных
При присвоении значения неопределенной локальной переменной используется или создается глобальная переменная.
function foo() { a = 2; b = 3; return a+b; } alert(a); // undefined a = 'очень важное значение'; alert(a); // очень важное значение foo(); alert(a); // 2
Таким образом можно легко затереть лишнего. По-моему такое поведение абсолютно нелогично, но, что ж, это не самое странное место яваскрипта. В любом случае неявного определения переменных стоит избегать.
Явно объявлять переменные можно и нужно ключевым словом
var
.var a = 2;
Такая строка всегда создает новую локальную переменную. Если объявление происходит вне функций, то она будет глобальной, что вполне логично.
function foo() { var a = 2; var b = 3; return a+b; } alert(a); // undefined var a = 'очень важное значение'; alert(a); // очень важное значение foo(); alert(a); // очень важное значение
Как объявить глобальную переменную из функции? Как обратиться к глобальной переменной, если есть локальная с таким же именем? Очень просто — нужно обратиться к ней как к свойству
window
:function foo() { var location = 'location'; alert(location); // вернет 'location' alert(window.location); // вернет window.location window.a = 'переменная из функции'; } alert(a); // undefined foo(); alert(a); // переменная из функции
Наследование области видимости
Меня всегда смущало то, что в Javascript можно определять функции внутри функций, а использовать их потом где угодно. Ну да, если посмотреть, точно то же самое можно делать в Ruby, и, наверное, во многих других языках тоже.
Переменные при этом передаются очень просто: если на момент определения функции переменная существовала, то она будет существовать и внутри функции. Откуда бы ее не вызывали.
function alertOnTimeout(message, timeout) { return setTimeout(function() { // message будет доступен в безымянной функции, переданной таймауту alert(message); }, timeout); }
Передача кода по старинке — строкой, которая прогоняется через
eval()
— не попадает под это правило, код исполняется в той области видимости, где и определен.Поскольку объекты в Javascript — это тоже типа функции, то свойство объекта определяется точно так же, как и переменная.
function myObject() { var property = 0; // Cамо собой, property будет доступно только внутри объекта. }
А еще в Javascript область видимости переменной ограничивается только функциями, а не блоками типа
if
(привет, Паскаль). Потому удобнее всего объявлять переменные в начале функции.this
А что
this
? А то, что эта переменная автоматически появляется в методах объектов и затирает значение this из предыдущей области видимости. Решение простое — переприсваивать ее значение другой переменной. $('div.with-links').click(function() { var theDiv = this; //сохраняем значение this $(this).find('a').click(function() { alert($(this).attr('href')); // this - это ссылка theDiv.remove(); // а theDiv - это все еще дивак }); });
Отдельно замечу, что при оборачивании какой-то поведенческой логики в объект надо помнить, что в создаваемых DOM-событиях значение this самого объекта теряется.
function myObject() { var _this = this; // сохраняем ссылку на родительский объект var linkRemoved = false; $('a').click(function() { $(this).remove(); // this - это объект ссылки _this.linkRemoved = true; // _this - это родительский объект }); }