Переменные и константы в JavaScript

Переменные в JavaScript

Переменная - это «именованное хранилище» для данных, которое используется для хранения изменяющейся (или постоянной) информации.

Объявление (declared) переменной означает её поименование (тип в JavaScript определяется динамически). Если переменная объявлена без начального значения, то она еще не готова полностью к работе.

Инициализация (initialization) переменной означает, что переменная объявлена, ей присвоено начальное значение и она запущена в работу. Без присвоения начального значения переменная просто объявлена, а с начальным значением она еще и инициализирована.

Создание (объявление и инициализация) переменной в JavaScript с использованием ключевого слова "let"

Ключевое слово let присоединяет объявление переменной к области видимости того блока (обычно пара { .. }), в котором оно содержится. Объявления, сделанные с помощью let, не поднимаются во всей области видимости блока, в котором они появляются. Такие объявления не "существуют" в блоке до оператора объявления, поэтому неправильное объявление (т.е. обращение к переменной до её объявления) вызовет ошибку:

Варианты объявления и инициализации

Несколько переменных в одной строке:

Такой способ может показаться короче, но для лучшей читаемости объявляйте каждую переменную на новой строке.

Многострочный вариант немного длиннее, но легче для чтения:

Или с одним let и запятыми:

Или с одним let и запятыми в начале строк:

Все эти варианты работают одинаково. 

[свернуть]
Ключевое слово let в циклах

let в заголовке цикла for будет объявлена не один раз для всего цикла, а для каждой итерации. И, она, конечно же, будет инициализирована в каждой последующей итерации значением с окончания предыдущей итерации:

[свернуть]

Особенности использования let:

  1. let не позволяет обратиться к переменной до её инициализации;
  2. let препятствует объявлению в одной области видимости переменных (и/или функций) с одинаковым именем.
  3. let является блочной или локальной (видна только внутри блока с областью видимости, ограниченной текущим блоком кода).

Возможные ошибки при использовании let (для кода ниже):

Создание (объявление и инициализация) переменной в JavaScript с использованием ключевого слова "var"

Ключевое слово var – почти то же самое, что и let. Оно объявляет переменную, но немного по-другому, «устаревшим» способом.

Особенности использования var:

  1. var не препятствует объявлению переменных с одинаковым именем (берется или функция, или последнее значение переменной; пример - ниже).
  2. Область видимости переменных var ограничивается либо функцией, либо, если переменная глобальная, то скриптом. Такие переменные доступны за пределами блока.
  3. Если блок кода находится внутри функции, то var становится локальной переменной в этой функции.

Особенности использования дублированных именований переменных и функций, объявленные с использованием var:

Ключевое слово var в циклах

var в заголовке цикла for не может быть блочной или локальной внутри цикла:

[свернуть]

Константы в JavaScript

В дополнение к let ES6 представляет ключевое слово const, которое также создает переменную блочной области видимости, но чье значение фиксировано (константа). Любая попытка изменить это значение позже приведет к ошибке.

Особенности использования констант:

  1. Константа должна быть сразу инициализирована (а не только объявлена).
  2. Константа не может быть переопределена.

Имена переменных и констант в JavaScript

Ограничения, касающиеся имён переменных JavaScript:

  1. Имя переменной должно содержать только буквы, цифры или символы $ и _.
  2. Первый символ не должен быть цифрой.
  3. Регистр букв имеет значение (apple и AppLE – это две разные переменные).
  4. Разрешен любой язык, включая кириллицу или даже иероглифы (но не рекомендуется).
  5. Существует список зарезервированных слов, которые нельзя использовать в качестве имён переменных, т.к. они используются самим языком (например: let, class, return, function).

Если имя содержит несколько слов, обычно используется CamelCase («ВерблюжийРегистр»), то есть слова следуют одно за другим, где каждое следующее слово начинается с заглавной буквы.

Примеры допустимых имён JavaScript:

Общепринятые правила именования переменных:

  1. Используйте легко читаемые имена, такие как userName или shoppingCart.
  2. Избегайте использования аббревиатур или коротких имён, таких как a, b, c, за исключением тех случаев, когда вы точно знаете, что так нужно.
  3. Делайте имена максимально описательными и лаконичными. Примеры плохих имён: data и value. Такие имена ничего не говорят. Их можно использовать только в том случае, если из контекста кода очевидно, какие данные хранит переменная.
  4. Договоритесь с вашей командой об используемых терминах. Если посетитель сайта называется «user», тогда мы должны называть связанные с ним переменные currentUser или newUser, а не, к примеру, currentVisitor или newManInTown.

Обычно буквы в верхнем регистре для поименования констант или переменных используются в том случае, когда значение известно до выполнения скрипта и записывается непосредственно в код, например:

Если переменная вычисляется во время выполнения скрипта, то используют нижний регистр:

Поднятие переменных (hoisting)

Области видимости (как функции, так и блока) работают по правилу:

  • любая переменная, объявленная в области видимости, присоединяется к этой области видимости.

Можно предположить, что весь код, который вы видите в программе на JavaScript, интерпретируется строка за строкой. Несмотря на то, что по сути это правда, есть одна часть этого предположения, которая может привести к некорректному пониманию вашей программы.

На самом деле движок JavaScript скомпилирует ваш код до того, как начнет интерпретировать его. Частью фазы компиляции является нахождение и ассоциация всех объявлений с их соответствующими областями видимости (подробнее здесь).

Поэтому целесообразно рассматривать, что все объявления как переменных, так и функций, обрабатываются в первую очередь, до того как будет выполнена любая часть кода.

Например:

Но если мы немного изменим код, то получим иной результат:

Когда мы видим var a = 2;, то думаем о нем как об одном операторе. Но JavaScript на самом деле обрабатывает его как два оператора:  

  1. var a; - первый оператор (объявление) обрабатывается во время фазы компиляции;
  2. и a = 2; - второй оператор (присваивание) остается на своем месте в фазе исполнения.

Получается, что объявления переменной или функции "переезжают" с того места, где они появились в коде в начало кода. Это явление имеет название "поднятие (hoisting)".

ВАЖНО! Каждое поднятие соотносится с областью видимости.

Пример с функцией:

Объявление функции foo (которое в этом случае включает в себя соответствующее значение как актуальную функцию) поднимается, благодаря чему ее вызов в первой строке может быть выполнен.

Поднимаются только сами объявления (сначала - функции, затем - переменные), тогда как любые присваивания или другая логика выполнения остается на месте. Если поднятие намеренно используется, чтобы перестроить логику выполнения вашего кода, то это может вызвать хаос.

ВАЖНО! Объявления функций поднимаются, а функциональные выражения — нет.

foo(); // не ReferenceError, но TypeError!

var foo = function bar() {
// ...
};
Идентификатор переменной foo поднимается и присоединяется к включающей его области видимости (глобальной) этой программы, поэтому foo() не вызовет ошибки ReferenceError. Но в foo пока еще нет значения (как если бы это было объявление обычной функции вместо выражения). Поэтому, foo() пытается вызвать значение undefined, которое является неправильной операцией с вызовом ошибки TypeError.

Также помните, что даже если это именованное функциональное выражение, идентификатор имени недоступен в окружающей области видимости:

foo(); // TypeError
bar(); // ReferenceError

var foo = function bar() {
// ...
};
Этот код более точно интерпретируется (с учетом поднятия) как:

var foo;

foo(); // TypeError
bar(); // ReferenceError

foo = function() {
var bar = ...self...
// ...
}
Сначала функции
Как объявления функций, так и переменных поднимаются. Но тонкость (которая поможет объяснить множественные объявления "дубликатов" в коде) в том, что сперва поднимаются функции, а затем уже переменные.

Представим:

foo(); // 1

var foo;

function foo() {
console.log( 1 );
}

foo = function() {
console.log( 2 );
};
1 выводится вместо 2! Этот код интерпретируется Движком так:

function foo() {
console.log( 1 );
}

foo(); // 1

foo = function() {
console.log( 2 );
};
Обратите внимание, что var foo является дублем объявления (и поэтому игнорируется), даже несмотря на то, что идет до объявления function foo()..., потому что объявления функций поднимаются до обычных переменных.

В то время как множественные/дублирующие объявления var фактически игнорируются, последовательные объявления функции перекрывают предыдущие.

foo(); // 3

function foo() {
console.log( 1 );
}

var foo = function() {
console.log( 2 );
};

function foo() {
console.log( 3 );
}
Несмотря на то, что всё это может прозвучать как не более чем любопытный академический факт, это привлекает тем, что дубли определений в одной и той же области видимости — в самом деле плохая идея и часто приводит к странным результатам.

Объявления функций, которые появляются внутри обычных блоков, обычно поднимаются в окружающей области видимости, вместо того чтобы быть условными как показывает код ниже:

foo(); // "b"

var a = true;
if (a) {
function foo() { console.log( "a" ); }
}
else {
function foo() { console.log( "b" ); }
}
Однако, важно отметить, что такое поведение небезопасно и может измениться в будущих версиях JavaScript, поэтому лучше избегать объявления функций в блоках.

Обзор
У нас есть соблазн смотреть на var a = 2; как на один оператор, но Движок JavaScript видит это по-другому. Он видит var a и a = 2 как два отдельных оператора, первый — как задачу фазы компиляции, а второй — как задачу фазы выполнения.

Это приводит к тому, что все объявления в области видимости, независимо от того где они появляются, обрабатываются первыми, до того, как сам код будет выполнен. Можно мысленно представить себе это как объявления (переменных и функций), "переезжающие" в начало их соответствующих областей видимости, что мы называем "поднятие (hoisting)".

Сами объявления поднимаются, а присваивания, даже присваивания функциональных выражений, не поднимаются.

Остерегайтесь дублей объявлений, особенно смешанных обычных объявлений var и объявлений функций — вас будут поджидать неприятности!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.