Область видимости переменной в Javascript
оригинал:http://habrahabr.ru/post/78991/
Для меня одним из самых проблемных мест Javascript было управление переменными. Излагаю простым русским языком.
Области видимости переменных
Переменные в 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 - это родительский объект }); }