Блог

Var vs let, const+

Tatiana Semchenko
0

Не многие знают, что на создание языка программирования JavaScript у Брендан Эйха ушло 10 дней. Такие сжатые сроки не лучшим образом повлияли на реализацию области видимости в столь популярном языке. Очень долго эта тема не поднималась в обсуждениях по причине отсутствия инструментов, необходимых для преодоления трудностей. Однако ECMAScript 6 расширил круг возможностей контроля области видимости переменных. Они уже хорошо поддерживаются браузерами и успешно используются большинством программистов. Но с появлением новых инструментов для объявления переменных сформировался и ряд вопросов. Ведь предыдущее ключевое слово var тоже осталось в арсенале JS. Когда же оправдано применение let и const? Существует ли необходимость использования var?

Области видимости переменных в JS

Под областью видимости (далее — ОВ) понимается часть программного кода, содержащего в своем теле обращения к этой переменной. Сложности с ней часто возникают у новичков.

Рассмотрим на конкретном примере:

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

Теперь рассмотрим следующий вариант кода:

Изменения в коде практически незаметны, но переменная была нами объявлена внутри самой функции. В этом случае console.log не покажет результата, и во время обращения к переменной на экране появится сообщение об ошибке ReferenceError. Причина — myVar объявлена внутри функции. В этом случае ОВ переменной ограничивается функцией, в которой она определена. MyVar становится недоступна извне, использовать ее можно только внутри данной функции. Чтобы несколько функций одного уровня могли совершить обращение к какой-либо общей переменной, объявлять ее нужно в той же части, в которой находятся данные функции — на уровень выше, чем их внутренние ОВ.

Неоспоримый факт: программный код большинства проектов — от сайтов до приложений — результат работы не одного программиста, а целой команды разработчиков с использованием сторонних библиотек и фреймворков. Даже если при разработке какого-либо веб-сайта задействован один разработчик, он, как правило, использует внешние ресурсы. Поэтому не рекомендовано объявлять переменные в той зоне видимости, которая относится к глобальному уровню — нельзя предугадать, объявление каких переменных будут делать другие программисты в проектном коде. Проблема решается инкапсулированием данных и функций или применением паттерна «Модуль» и IIFE при объектно-ориентированном подходе. Однако, переменные с выходящей за пределы необходимого областью видимости могут стать настоящей проблемой для разработчика.

Недостатки var

Раз с ОВ мы разобрались, рассмотрим более сложные моменты. Взглянем на пример ниже:

После выполнения кода консоль будет выводить нам растущие значения счетчика i внутри цикла: 0, 1 и 2. Завершив цикл, программа совершает попытку обращения к этому счетчику за пределами цикла for, где он объявлен. Var находится на уровне функции, консоль выведет значение 3. При объявлении переменной через var обращаться к ней можно и за пределами блока, в котором она была объявлена.

Проблема возникает при усложнении функций. Рассмотрим код ниже:

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

На этом основана главная особенность ключевого слова Var, которая делает ее использование проблематичным. Все переменные, которые были объявлены посредством var, имеют довольно широкую ОВ. На выходе их значения перезаписываются, в результате появляются различные ошибки. Отлично, когда ОВ переменной совпадает с той, которая ей необходима. Такая возможность теперь доступна в ECMAScript 6. Это позволяет создавать более стабильные конструкции кода, защищенные от подобных ошибок.

Новые ключевые слова

С появлением стандарта ES6 (ECMAScript 6) разработчики получили в свой арсенал два функциональных ключевых слова — let и const. Существенное отличие от var в том, что они имеют более ограниченную, блочную ОВ и дают разработчику возможность гибко ограничивать ОВ переменных блоком кода, например, циклом for или конструкцией if.

Как использовать let

Let очень схоже с var. Разница в том, что переменные, объявленные посредством let, обладают ограниченной ОВ. Посмотрим, что произойдет после замены var на let в вышеприведенном примере:

Теперь консоль выведет значения 2 и 1, так как вторая переменная находится вне зависимости от первой и обладает другой ОВ, которая ограничена с помощью блока if. При этом, обособленные блоки кода, например, конструкция if, могут обратиться к переменным, которые объявлены на этом же уровне, т.к. они не изолированы. Смотрите:

Консоль выведет число 1. Для кода внутри конструкции if доступна переменная, созданная вне ее. Она и выводится. Давайте попробуем перемешать ОВ:

Думаете, что console.log первым вызовом выведет 1? Вы увидите ошибку ReferenceError при попытке выполнения кода, сообщающую, что myVar не определяется или не инициализируется (в различных браузерах текст немного отличается) для этой ОВ.

В JavaScript резервируется место, в котором будет объявлена переменная, независимо от ОВ. Резерв происходит еще до момента указания имени и типа переменной. То есть JS отводит для них верхнюю часть ОВ. Алгоритм объявления отличается для var и let.

Перейдем к наглядному примеру:

Указанные случаи предусматривают, что переменная используется до ее объявления. Но консоль выводит данные по-разному. В первом случае, при использовании переменной, позднее объявленной при помощи var, выводится undefined. А конкретнее — информация, занесенная в переменную. Вторая используемая команда, в которой позже используется let, отобразит ReferenceError и предупредит, что переменная используется прежде объявления и инициализации. Почему так происходит?

Ответ прост. Перед тем, как приступить к выполнению кода, специальные механизмы просматривают его, определяют, будут ли в дальнейшем объявляться переменные. Если да, то производится их поднятие и резервируется место. Все объявленные при помощи var переменные будут определяться как undefined в границах области своей видимости. Результат будет одним и тем же, даже если обращение производится до объявления переменной. Но есть проблема: вывод значения undefined не всегда означает, что производится попытка использования переменной до инициализации. Рассмотрим пример:

Объявление var 1 и 2 выполняется по-разному. Но при обращении к console.log программист увидит одно и тоже — появится undefined. Объяснить это просто. Любым неинициализированным переменным, объявление которых производится при использовании var, присваивается значение undefined. Но если обращение проводится до момента объявления, на выходе все равно выдается значение undefined. И при наличии ошибки в коде понять, что послужило причиной (отсутствие инициализации или объявления переменной), будет непросто.

За объявленными при помощи let переменными автоматически закрепляется место в блоке. Но до момента объявления они находятся во временной мертвой зоне или TDZ. Обратиться к ним до объявления не получится, а если попытаться, система выдаст сообщение об ошибке. В нем также будет содержаться информации о причине возникновения сбоя. Доказательство представлено на примере:

Первое обращение приведет к выводу undefined. А второе — спровоцирует появление ошибки ReferenceError. Ее причиной выступает необъявленная или неинициализированная переменная.

Делаем вывод из вышесказанного. Если используется var, то при выводе undefined понять причину сложно. Истоки могут крыться в использовании неинициализированной или необъявленной переменной. Также появление undefined иногда означает, что переменная не объявлена в зоне видимости. Но стоит учитывать, что она вполне может быть объявлена в следующей за командой обращения части кода. А вот если использовать ключевое слово let, то распознать причину ошибки и сделать отладку намного легче.

Как использовать const

Ключевые слова const и let работают по одному принципу. Их отличает только то, что const применяется, чтобы объявить константы, значения которых не изменяются после объявления. Впрочем, изменение невозможно только для самых простых констант, таких как строка или число. Сложные константы, такие как объект или массив, можно модифицировать по внутренней структуре. Заменить же одну структуру на другую не представляется возможным.

Рассмотрим данный код:

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

Попробуем изучить константу, в которой прописана ссылка на кнопку:

В случае зависимости кода от ссылки на HTML-элемент необходимо сохранить эту ссылку без изменений. Тогда напрашивается вывод, что const это не только новые возможности улучшения видимости переменных, но еще и сужение возможностей по изменению констант, для написания которых был использовано это ключевое слово. При этом, хочется рекомендовать разработчикам продумать такие возможности модификации переменных, которые необходимы только для обеспечения корректной работы кода. Остальные возможности модификаций стоит ограничить. Резюмируя сказанное, возможность мутации переменных заставляет программистов скрупулезно продумывать каждый элемент кода перед написанием. В итоге мы получаем более чистый и правильный код и меньшую вероятность возникновения непредсказуемого результата.

Используя ключевые слова let и const в самом начале практики, некоторые разработчики больше используют let. Но с повышением опыта программисты открывают для себя возможности использования const. Поэтому опытные разработчики больше пользуются const, прописывая ключевое слово let только в случае необходимости перезаписать переменную.

Нужно ли нам ключевое слово var

Let и const применяются в условиях повышенной ответственности. Все же остаются моменты, в которых применение var остается актуальным. Повсеместная замена var на let или const не всегда оправдана, поэтому, прежде чем менять ключевые слова, стоит тщательно проанализировать ситуацию.

Уровень поддержки ключевого слова var браузерами

С помощью var можно объявить переменные, которые будут поддерживаться всеми браузерами без исключения. Это значимый фактор, который отличает var от let или const. При объявлении переменных посредством let или const существует вероятность попасть в ситуацию, когда созданная программа не будет поддерживаться отдельными браузерами. Даже несмотря на то, что эти ключевые слова адаптируются в большинстве браузеров.

Наглядно рассмотреть такую ситуацию можно, сравнив отсутствие поддержки JavaScript-кода и реакцию браузеров на нераспознанный CSS-код.
В случае, когда браузер не может распознать CSS-код, вы можете столкнуться с искажением информации на экране. Если браузер не поддерживает некоторые стилистические особенности сайта, то это вероятнее всего не скажется на его работоспособности. В большинстве случаев страдать будет только визуальное оформление, которое будет отличаться от того, что вы рассчитывали увидеть.

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

В большинстве случаев эта проблема не представляет серьезной угрозы, так как использование устаревших браузеров сокращается с каждым днем. Но иногда, когда речь идет о госструктурах и предприятиях, где используются устаревшие браузеры, проблема может стать глобальной. Поэтому, прежде чем отказываться от var в пользу let и const, стоит оценить вероятность риска.

Все же существует возможность оптимизации новых возможностей ES6 и ключевых слов let и const под старые браузеры. Одним из способов оптимизации является использование JavaScript-транспилятора (типа Babel). Транспилятор способен конвертировать новый код в такой, который будет считываться устаревшими браузерами. С помощью Babel появляется возможность писать современный код с последними возможностями, после чего переводить его в понятный для всех браузеров.

Данная способность транспиляторов была бы идеальна, если бы не таила в себе подвох. Неприятной особенностью использования Babel является значительное увеличение объема кода, в сравнении с тем, который был написан вручную. В итоге это приводит к повышенному объему файлов. Еще одна неприятная особенность — привязка к транспилятору вашего документа. ES6-код способен обрабатываться Babel практически идеально, но даже его в случае отказа от транспилятора придется проверять и заново тестировать. Для проектов, работающих без нареканий, такая перспектива достаточно непривлекательна. Поэтому, прежде чем решиться на использование транспилятора, стоит определиться: планируется ли переработка кодовой базы и когда, через какое время поддержка браузеров типа IE8 потеряет свою актуальность.

Использование var для решения одной специфической задачи

В решении некоторых, достаточно специфических задач, ключевое слово var остается незаменимым. К примеру:

При объявлении переменной myVar в области глобальной видимости иногда к ней теряется доступ, к примеру, если эта же переменная была объявлена в функции. Впоследствии может возникнуть проблема, что переменную нужно достать из области глобальной видимости. Если в некоторых случаях проблему можно решить путем передачи первой переменной в функцию или изменением наименования одной из них, то в исключительных ситуациях вы можете столкнуться с тем, что ни одна из переменных не будет доступна. Тогда на помощь приходит функциональность Var:

Var устроено таким образом, что при объявлении переменной в глобальной области видимости эта переменная привяжется к глобальному объекту window автоматически. У ключевых слов let и const данная возможность отсутствует. Пусть нечасто, но иногда эта возможность Var оказывается крайне необходимой. К примеру, может возникнуть ситуация, когда при проверке сборочного JS-кода, необходимого для объединения файлов, ссылка на глобальную переменную в одном из файлов выдает ошибку. Эта ошибка мешает объединению файлов и требует срочного устранения.

Но у этой возможности Var есть свои недостатки: она приводит к тому, что написанный код получается неаккуратным. Опытные программисты решают данную проблему другим способом: переменные в виде свойств они записывают в отдельный объект, таким образом, код выходит аккуратнее, а вероятность ошибки гораздо меньше:

В этом случае код получается понятнее, но длиннее.

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

Итоги

Когда использовать var

Если необходима поддержка IE10 и устаревших браузеров, а вы не хотели бы применять транспиляторы, то на данном этапе стоит отказаться от новых ключевых слов в пользу Var.

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

Когда использовать let и const

Во всех остальных случаях. Ключевое слово let — для объявления переменных и const — для объявления констант позволят вам написать красивый, чистый и гибкий код, отличающийся большей стабильностью и меньшей подверженности ошибкам.

Вы готовы попробовать новые возможности JavaScript? Тогда сделайте первый шаг: попробуйте заменить Var на const везде в своем коде. При возникновении необходимости перезаписать переменную, используйте let (эта мера может не пригодиться, если вы планируете переписывать код).

Для чего нужны let и const

Данные ключевые слова, которые появились в ECMAScript 6, открывают новые возможности в области контроля за видимостью констант и переменных в коде веб-сайтов и веб-приложений. Let и const — довольно новое явление в программировании, поэтому использовать их целесообразно только после тщательного изучения необходимости применения в рамках конкретно поставленной задачи. Если же принято решение использовать эти ключевые слова, то они помогут стабилизировать работу проектов и подготовить их к изменениям.

0