Конспект по Javascript
2 Переменные, область видимости
Переменные
Переменная - это имя для некоторого значения. В JavaScript переменные имеют слабую типизацию и могут хранить значение любого типа. Имя переменной служит пояснением ее роли в модели программы, поэтому очень важно давать переменным осмысленные имена.
В JavaScript переменная создается в момент записи значения в выполняющемся скрипте, даже если она не была явно объявлена. Однако это плохой стиль, который иногда может приводить к ошибкам: у переменных бывает разная область видимости и автоматически созданная переменная может принадлежать не той области.
Название переменной должно начинаться с буквы или знака подчеркивания. Дальше могут идти буквы, цифры и знак подчеркивания. Некоторые ключевые слова нельзя использовать в качестве названия переменной. Некоторые реализации языка могут поддерживать кириллические буквы в названиях переменных и функций, но пользоваться этим категорически нельзя: такой скрипт будет работать не везде. Буквы надо выбирать исключительно из английского алфавита, даже если ваш браузер понимает и другие.
В скриптовых языках длина имени переменной влияет на скорость обработки, поэтому не стоит переусердствовать. Но и полностью переходить на однобуквенные имена не стоит: это очень усложнит разработку.
Примеры создания переменных:
- i = 0;
- Переменная i создается автоматически в глобальной области, если еще не существует. Затем ей присваивается значение 0.
- var k, m;
- Создаются переменные k и m в текущей области видимости. Они имеют тип undefined.
- var p = "abc", q;
- Создаются переменные p и q в текущей области видимости. Переменная p получает значение "abc" и тип String, а переменная q имеет неопределенный тип.
Удаление переменной
Ненужную переменную или поле объекта можно удалить оператором delete:
delete i;
delete obj.field;
Заморочки с объявленными / необъявленными / несуществующими переменными
Если переменная объявлена, но не имеет значения, то ее тип "undefined" и значение undefined и ее можно использовать.
Если переменная не объявлена и не назначена, она не существует и ее нельзя использовать. Но оператор typeof вернет ее тип как "undefined".
Область видимости
Область видимости имени переменной или функции в JavaScript почти всегда регулируется контекстным объектом для текущего места скрипта.
- Глобальные переменные создаются в объекте Window, который представляет текущую вкладку браузера. Поэтому не рекомендуется злоупотреблять объявлением глобальных переменных и функций: это замедляет работу скрипта и может мешать скриптам других джигитов, которые объявляют глобальные переменные и функции с тем же именем. Сейчас все чаще используется динамическая работа страницы, когда сама страница загружается только один раз, а затем уже подгружает нужные данные и скрипты, заменяя их по мере необходимости. "Забытые" переменные и функции замедляют работу и усложняют отладку: часто программа работает в одной и той же последовательности, благодаря чему неправильную подгрузку тестировщик не заметит (ложный успех).
- Локальные переменные функций создаются в специальном объекте __SCOPE__, который создается для каждого вызова функции. После выхода из функции и если на этот объект никто не ссылается, он уничтожается системой. Создание объекта на каждый вызов функции делает вызовы функций в JavaScript довольно дорогостоящим удовольствием, но зато позволяет делать интересные вещи вроде замыканий. Чтобы переменная была создана в локальной области, ее необходимо объявить через оператор var. Иначе будет использоваться или создастся глобальная переменная. Локальная переменная доступна во всем теле функции вне зависимости от места объявления, что часто приводит к логическим ошибкам. В следующем примере переменная a создается не в момент входа в блок if, а сразу при запуске функции:
function f() { //f: a = undefined document.write("<br />f: a = " + a); if(a == 0) { var a = 5; } } var a = 0; //global: a = 0 document.write("<br />global: a = " + a); f();
- Поля объектов. Поле данных, поле доступа или метод объекта - это тоже переменная, которая хранится в своем объекте. Она также автоматически доступна для объектов, которые используют данный объект как прототип. Поля объектов обычно уничтожаются вместе с объектом, но их также можно удалять оператором delete.
- Блочные переменные. Начиная с версии JavaScript 1.7 можно объявлять переменные, которые видимы только в своем блоке, причем они могут перекрывать переменные из внешнего блока. Для объявления блочной переменной используется оператор let. Это новая функциональность и она доступна только в последних версиях браузеров: например, IE11. Firefox требует наличия версии языка в объявлении скрипта, иначе скрипт не выполняется.
<script type="application/javascript;version=1.7"> //outer //inner //outer let a = "outer"; document.write("<br />" + a); if (a == "outer") { let a = "inner"; document.write("<br />" + a); } document.write("<br />" + a) </script>
- Блочные константы. Блочная константа - это переменная, которая не может изменяться после объявления. Она также ограничена текущим блоком и может переопределяться во внутренних блоках. Это также новая функциональность, доступная только в последних версиях браузеров. Константа объявляется также, как и переменная, но с оператором const.
Замыкания
Благодаря хранению локальных переменных в особом объекте, эти переменные могут использоваться даже после выхода из функции. Это часто используется при объявлении функции внутри другой функции. Чаще всего это используется в функциях, которые добавляют обработчики событий для объектов. Запустив функцию с необходимыми для обработчиков параметрами, мы можем быть уверены, что эти данные будут видимы, когда понадобятся.
function addHideHandler(btnId, targetId)
{
var handler = function()
{
document.getElementById(targetId).style.display = ‘none’;
};
document.getElementById(btnId).onclick = handler;
}
В этом примере мы назначаем некоему тегу "кнопке" обработчик onclick, который скрывает другой тег с ID = targetId. Как мы видим, параметр btnId используется в функции для определения нужной кнопки. Мы просто находим эту кнопку, назначаем ей обработчик и выходим из функции - никаких вопросов к этому параметру нет. А вот параметр targetId используется гораздо позже. Когда функция давно отработала и пользователь наконец-то нажал кнопку. В обычных стековых языках локальные переменные функции после ее выхода уничтожаются. Сама стековая архитектура не позволяет им существовать: на их месте должны быть (не могут случайно, а должны быть) уже другие переменные, от других функций. Благодаря хранению переменных во внешнем объекте и механизму замыкания, локальные переменные этой функции не будут уничтожены, пока существуют объекты, ссылающиеся на них.
Технология замыканий используется и в других языках: в C# она тоже стала популярной благодаря популярности лямбда-выражений.