Javascript чем var отличается от let
Перейти к содержимому

Javascript чем var отличается от let

  • автор:

Переменные

JavaScript-приложению обычно нужно работать с информацией. Например:

  1. Интернет-магазин – информация может включать продаваемые товары и корзину покупок.
  2. Чат – информация может включать пользователей, сообщения и многое другое.

Переменные используются для хранения этой информации.

Переменная

Переменная – это «именованное хранилище» для данных. Мы можем использовать переменные для хранения товаров, посетителей и других данных.

Для создания переменной в JavaScript используйте ключевое слово let .

Приведённая ниже инструкция создаёт (другими словами: объявляет или определяет) переменную с именем «message»:

Теперь можно поместить в неё данные, используя оператор присваивания = :

Строка сохраняется в области памяти, связанной с переменной. Мы можем получить к ней доступ, используя имя переменной:

Для краткости можно совместить объявление переменной и запись данных в одну строку:

Мы также можем объявить несколько переменных в одной строке:

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

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

Некоторые люди также определяют несколько переменных в таком вот многострочном стиле:

…Или даже с запятой в начале строки:

В принципе, все эти варианты работают одинаково. Так что это вопрос личного вкуса и эстетики.

В старых скриптах вы также можете найти другое ключевое слово: var вместо let :

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

Есть тонкие различия между let и var , но они пока не имеют для нас значения. Мы подробно рассмотрим их в главе Устаревшее ключевое слово "var".

Аналогия из жизни

Мы легко поймём концепцию «переменной», если представим её в виде «коробки» для данных с уникальным названием на ней.

Например, переменную message можно представить как коробку с названием "message" и значением "Hello!" внутри:

Мы можем положить любое значение в коробку.

Мы также можем изменить его столько раз, сколько захотим:

При изменении значения старые данные удаляются из переменной:

Мы также можем объявить две переменные и скопировать данные из одной в другую.

Переменная может быть объявлена только один раз.

Повторное объявление той же переменной является ошибкой:

Поэтому следует объявлять переменную только один раз и затем использовать её уже без let .

Примечательно, что существуют функциональные языки программирования, такие как Scala или Erlang, которые запрещают изменять значение переменной.

В таких языках однажды сохранённое «в коробку» значение остаётся там навсегда. Если нам нужно сохранить что-то другое, язык заставляет нас создать новую коробку (объявить новую переменную). Мы не можем использовать старую переменную.

Хотя на первый взгляд это может показаться немного странным, эти языки вполне подходят для серьёзной разработки. Более того, есть такая область, как параллельные вычисления, где это ограничение даёт определённые преимущества. Изучение такого языка (даже если вы не планируете использовать его в ближайшее время) рекомендуется для расширения кругозора.

Имена переменных

В JavaScript есть два ограничения, касающиеся имён переменных:

  1. Имя переменной должно содержать только буквы, цифры или символы $ и _ .
  2. Первый символ не должен быть цифрой.

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

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

Самое интересное – знак доллара ‘$’ и подчёркивание ‘_’ также можно использовать в названиях. Это обычные символы, как и буквы, без какого-либо особого значения.

Эти имена являются допустимыми:

Примеры неправильных имён переменных:

Переменные с именами apple и APPLE – это две разные переменные.

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

Технически здесь нет ошибки, такие имена разрешены, но есть международная традиция использовать английский язык в именах переменных. Даже если мы пишем небольшой скрипт, у него может быть долгая жизнь впереди. Людям из других стран, возможно, придётся прочесть его не один раз.

Существует список зарезервированных слов, которые нельзя использовать в качестве имён переменных, потому что они используются самим языком.

Например: let , class , return и function зарезервированы.

Приведённый ниже код даёт синтаксическую ошибку:

Обычно нам нужно определить переменную перед её использованием. Но в старые времена было технически возможно создать переменную простым присвоением значения без использования let . Это все ещё работает, если мы не включаем use strict в наших файлах, чтобы обеспечить совместимость со старыми скриптами.

Это плохая практика, которая приводит к ошибке в строгом режиме:

Константы

Чтобы объявить константную, то есть, неизменяемую переменную, используйте const вместо let :

Переменные, объявленные с помощью const , называются «константами». Их нельзя изменить. Попытка сделать это приведёт к ошибке:

Если программист уверен, что переменная никогда не будет меняться, он может гарантировать это и наглядно донести до каждого, объявив её через const .

Константы в верхнем регистре

Широко распространена практика использования констант в качестве псевдонимов для трудно запоминаемых значений, которые известны до начала исполнения скрипта.

Названия таких констант пишутся с использованием заглавных букв и подчёркивания.

Например, сделаем константы для различных цветов в «шестнадцатеричном формате»:

  • COLOR_ORANGE гораздо легче запомнить, чем "#FF7F00" .
  • Гораздо легче допустить ошибку при вводе "#FF7F00" , чем при вводе COLOR_ORANGE .
  • При чтении кода COLOR_ORANGE намного понятнее, чем #FF7F00 .

Когда мы должны использовать для констант заглавные буквы, а когда называть их нормально? Давайте разберёмся и с этим.

Название «константа» просто означает, что значение переменной никогда не меняется. Но есть константы, которые известны до выполнения (например, шестнадцатеричное значение для красного цвета), а есть константы, которые вычисляются во время выполнения сценария, но не изменяются после их первоначального назначения.

Значение pageLoadTime неизвестно до загрузки страницы, поэтому её имя записано обычными, а не прописными буквами. Но это всё ещё константа, потому что она не изменяется после назначения.

Другими словами, константы с именами, записанными заглавными буквами, используются только как псевдонимы для «жёстко закодированных» значений.

Придумывайте правильные имена

В разговоре о переменных необходимо упомянуть, что есть ещё одна чрезвычайно важная вещь.

Название переменной должно иметь ясный и понятный смысл, говорить о том, какие данные в ней хранятся.

Именование переменных – это один из самых важных и сложных навыков в программировании. Быстрый взгляд на имена переменных может показать, какой код был написан новичком, а какой – опытным разработчиком.

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

Пожалуйста, потратьте время на обдумывание правильного имени переменной перед её объявлением. Делайте так, и будете вознаграждены.

Несколько хороших правил:

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

Звучит просто? Действительно, это так, но на практике для создания описательных и кратких имён переменных зачастую требуется подумать. Действуйте.

И последняя заметка. Есть ленивые программисты, которые вместо объявления новых переменных повторно используют существующие.

В результате их переменные похожи на коробки, в которые люди бросают разные предметы, не меняя на них этикетки. Что сейчас находится внутри коробки? Кто знает? Нам необходимо подойти поближе и проверить.

Такие программисты немного экономят на объявлении переменных, но теряют в десять раз больше при отладке.

Дополнительная переменная – это добро, а не зло.

Современные JavaScript-минификаторы и браузеры оптимизируют код достаточно хорошо, поэтому он не создаёт проблем с производительностью. Использование разных переменных для разных значений может даже помочь движку оптимизировать ваш код.

Итого

Мы можем объявить переменные для хранения данных с помощью ключевых слов var , let или const .

  • let – это современный способ объявления.
  • var – это устаревший способ объявления. Обычно мы вообще не используем его, но мы рассмотрим тонкие отличия от let в главе Устаревшее ключевое слово "var" на случай, если это всё-таки вам понадобится.
  • const – похоже на let , но значение переменной не может изменяться.

Переменные должны быть названы таким образом, чтобы мы могли легко понять, что у них внутри.

Задачи

Работа с переменными

  1. Объявите две переменные: admin и name .
  2. Запишите строку "Джон" в переменную name .
  3. Скопируйте значение из переменной name в admin .
  4. Выведите на экран значение admin , используя функцию alert (должна показать «Джон»).

В коде ниже каждая строка решения соответствует одному элементу в списке задач.

Var, let или const? Проблемы областей видимости переменных и ES6

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

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

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

Взгляните на следующий пример:

Что выведет метод console.log ? Ответ на этот вопрос никого не удивит: он выведет 2 . Переменная myVar объявлена за пределами какой-либо функции, что говорит нам о том, что она объявлена в глобальной области видимости. Следовательно, любая функция, объявленная в той же области видимости, сможет обратиться к myVar . На самом деле, если речь идёт о коде, выполняемом в браузере, доступ к этой переменной будет даже у функций, объявленных в других файлах, подключённых к странице.

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

Внешне его изменения, по сравнению с предыдущим примером, незначительны. А именно, мы всего лишь поместили объявление переменной внутрь функции. Что теперь выведет console.log ? На самом деле, ничего, так как эта переменная не объявлена и при попытке обратиться к ней будет выведено сообщение о необработанной ошибке ReferenceError . Произошло так из-за того, что переменную, с помощью ключевого слова var , объявили внутри функции. В результате область видимости этой переменной ограничивается внутренней областью видимости функции. К ней можно обратиться в теле этой функции, с ней могут работать функции, вложенные в эту функцию, но извне она недоступна. Если нам надо, чтобы некоей переменной могли бы пользоваться несколько функций, находящихся на одном уровне, нам надо объявлять эту переменную там же, где объявлены эти функции, то есть — на один уровень выше их внутренних областей видимости.

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

Проблема ключевого слова var

Итак, мы разобрались с понятием «область видимости». Теперь перейдём к более сложным вещам. Взгляните на следующий код:

Что попадёт в консоль после его выполнения? Понятно, что внутри цикла будут выводиться значения увеличивающегося счётчика i : 0 , 1 и 2 . После того, как цикл завершается, программа продолжает выполняться. Теперь мы пытаемся обратиться к той же самой переменной-счётчику, которая была объявлена в цикле for , за пределами этого цикла. Что из этого выйдет?

В консоль, после обращения к i за пределами цикла, попадёт 3, так как ключевое слово var действует на уровне функции. Если объявить переменную с использованием var , то обратиться к ней в функции можно и после выхода из той конструкции, где она была объявлена.

Это может превратиться в проблему тогда, когда функции усложняются. Рассмотрим следующий пример:

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

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

Новые способы объявления переменных

Стандарт ECMAScript 6 (новый набор возможностей JavaScript, известный ещё как ES6 и ES2015) даёт нам два новых способа объявления переменных, отличающихся ограниченной, по сравнению с var , областью видимости и имеющих ещё некоторые особенности. Это — ключевые слова let и const . И то и другое даёт нам так называемую блочную область видимости. Это означает, что область видимости при их использовании может быть ограничена блоком кода, таким, как цикл for или выражение if . Это даёт разработчику больше гибкости в выборе областей видимости переменных. Рассмотрим новые ключевые слова.

▍Использование ключевого слова let

Ключевое слово let очень похоже на var , основное отличие — ограниченная область видимости переменных, объявляемых с его помощью. Перепишем один из вышеприведённых примеров, заменив var на let :

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

В этом примере в консоль попадёт число 1 . У кода, находящегося внутри выражения if есть доступ к переменной, которую мы создали за его пределами. Поэтому он и выводит её значение в консоль. А что произойдёт, если попытаться перемешать области видимости? Например, сделать так:

Может показаться, что первый вызов console.log выведет 1 , но на самом деле при попытке выполнить этот код появится ошибка ReferenceError , которая сообщает нам о том, что переменная myVar для данной области видимости не определена или не инициализирована (текст этой ошибки различается в разных браузерах). В JavaScript существует такое явление, как поднятие переменных в верхнюю часть их области видимости. То есть, если в некоей области видимости объявляют переменную, JavaScript резервирует место для неё ещё до того, как будет выполнена команда её объявления. То, как именно это происходит, различается при использовании var и let .

Рассмотрим следующий пример:

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

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

В данном случае, несмотря на то, что var1 и var2 объявлены по-разному, оба вызова console.log выведут undefined . Дело здесь в том, что в переменные, объявленные с помощью var , но не инициализированные, автоматически записывается значение undefined . При этом, как мы уже говорили, переменные, объявленные с помощью var , к которым обращаются до момента их объявления, так же содержат undefined . В результате, если в подобном коде что-то пойдёт не так, нельзя будет понять, что именно является источником ошибки — использование неинициализированной переменной или использование переменной до её объявления.

Место для переменных, объявляемых с помощью ключевого слова let , резервируется в их блоке, но, до их объявления, они попадают во временную мёртвую зону (TDZ, Temporal Dead Zone). Это приводит к тому, что ими, до их объявления, пользоваться нельзя, а попытка обращения к такой переменной приводит к ошибке. Однако система точно знает причину проблемы и сообщает об этом. Это хорошо видно на данном примере:

Здесь первый вызов console.log выведет undefined , а второй вызовет ошибку ReferenceError , сообщая нам о том, что переменная пока не объявлена или не инициализирована.

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

▍Использование ключевого слова const

Ключевое слово const очень похоже на let , но у них есть одно важное различие. Это ключевое слово используется для объявления констант. Значения констант после их инициализации менять нельзя. Нужно отметить, что это относится лишь к значениям примитивных типов, воде строки или числа. Если константа является чем-то более сложным, например — объектом или массивом, внутреннюю структуру подобной сущности модифицировать можно, нельзя лишь заменить её саму на другую. Взгляните на следующий код:

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

Возможно вам, как JavaScript-разработчику, интересно, почему иммутабельность переменных — это важно. Константы — это новое явление в JavaScript, в то время как они являются важнейшей частью таких языков, как C или Java. Почему эта концепция так популярна? Дело в том, что использование констант заставляет нас думать о том, как именно работает наш код. В некоторых ситуациях изменение значения переменной может нарушить работу кода, например, если в ней записано число Пи и к ней постоянно обращаются, или если в переменной имеется ссылка на некий HTML-элемент, с которым постоянно нужно работать. Скажем, вот константа, в которую записана ссылка на некую кнопку:

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

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

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

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

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

Переменные, объявленные с помощью ключевого слова var , отличаются одной очень важной особенностью, отсутствующей у let и const . А именно, речь идёт о том, что это ключевое слово поддерживают абсолютно все браузеры. Хотя поддержка браузерами let и const весьма хороша, однако, существует риск того, что ваша программа попадёт в браузер, их не поддерживающий. Для того чтобы понять последствия подобного происшествия, нужно учитывать то, как браузеры обходятся с неподдерживаемым JavaScript-кодом, в противовес, например, тому, как они реагируют на непонятный им CSS-код.

Если браузер не поддерживает какую-то возможность CSS, то это, в основном, ведёт к некоторым искажениям того, что будет выведено на экран. Сайт в браузере, который не поддерживает какие-то из используемых сайтом стилей, будет выглядеть не так, как ожидается, но им, весьма вероятно, можно будет пользоваться. Если же вы используете, например, let , а браузер это ключевое слово не поддерживает, то ваш JS-код там просто не будет работать. Не будет — и всё. Учитывая то, что JavaScript является одной из важных составных частей современного веба, это может стать серьёзнейшей проблемой в том случае, если вам надо, чтобы ваши программы работали бы в устаревших браузерах.

Когда говорят о поддержке сайтов браузерами, обычно задаются вопросом о том, в каком браузере сайт будет работать оптимально. Если же речь идёт о сайте, функционал которого основан на использовании let и const , то похожий вопрос придётся ставить иначе: «В каких браузерах наш сайт работать не будет?». И это — гораздо более серьёзно, чем разговор о том, использовать или нет display: flex . Для большинства веб-сайтов число пользователей с устаревшими браузерами не будет достаточно большим, чтобы об этом стоило бы беспокоиться. Однако если речь идёт о чём-то вроде интернет-магазина, или сайтов, владельцы которых покупают рекламу, это может быть весьма важным соображением. Прежде чем использовать новые возможности в подобных проектах, оцените уровень риска.

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

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

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

Есть ещё одна ситуация, в которой ключевое слово var может то, чего не могут другие. Это довольно специфическая задача. Рассмотрим следующий код:

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

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

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

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

Итоги

Итак, что выбрать? Как расставить приоритеты? Вот некоторые соображения по этому поводу:

  • Вы собираетесь поддерживать IE10 или по-настоящему старые браузеры? Если вы даёте на этот вопрос положительный ответ и не собираетесь пользоваться транспиляторами — отказывайтесь от новых возможностей и используйте var .
  • Если вы можете позволить себе использование новых возможностей JavaScript, начать стоит с того, чтобы везде, где раньше применялось ключевое слово var , использовать const . Если где-то нужна возможность перезаписи значения переменной (хотя, если вы попытаетесь переписать свой код, то эта возможность может вам и не понадобиться) — используйте let .

Уважаемые читатели! Согласны ли вы с рекомендацией, в соответствии с которой ключевое слово const стоит сделать основной заменой ключевому слову var , прибегая к let лишь в тех случаях, когда значение переменной, по объективным причинам, нужно перезаписывать?

Javascript чем var отличается от let

Директива let объявляет переменную с блочной областью видимости с возможностью инициализировать её значением.

Синтаксис

Параметры

Имя переменной. Может использоваться любой допустимый идентификатор.

value1 , value2 , …, valueN

Значение переменной. Любое допустимое выражение.

Описание

Директива let позволяет объявить локальную переменную с областью видимости, ограниченной текущим блоком кода . В отличие от ключевого слова var (en-US) , которое объявляет переменную глобально или локально во всей функции, независимо от области блока.

Объяснение, почему было выбрано название «let» можно найти здесь.

Правила области видимости

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

Чище код во вложенных функциях

let иногда делает код чище при использовании вложенных функций.

Пример выше будет выполнен как и ожидается, так как пять экземпляров внутренней функции (анонимной) будут ссылаться на пять разных экземпляров переменной i . Пример будет выполнен неверно, если заменить директиву let на var, или удалить переменную i из параметров вложенной функции и использовать внешнюю переменную i во внутренней функции.

На верхнем уровне скриптов и функций let, в отличии от var, не создаёт свойства на глобальном объекте . Например:

В выводе программы будет отображено слово «global_x» для this.x , но undefined для this.y .

Эмуляция приватных членов

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

Эта техника позволяет получить только «статичное» приватное состояние — в примере выше, все экземпляры полученные из конструктора SomeConstructor будут ссылаться на одну и ту же область видимости privateScope .

Временные мёртвые зоны и ошибки при использовании let

Повторное объявление той же переменной в том же блоке или функции приведёт к выбросу исключения SyntaxError.

В стандарте ECMAScript 2015 переменные, объявленные директивой let, переносятся в начало блока. Но если вы сошлётесь в блоке на переменную, до того как она объявлена директивой let, то это приведёт к выбросу исключения ReferenceError , потому что переменная находится во «временной мёртвой зоне» с начала блока и до места её объявления. (В отличии от переменной, объявленной через var , которая просто будет содержать значение undefined )

Вы можете столкнуться с ошибкой в операторах блока switch , так как он имеет только один подблок.

Использование let в циклах for

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

Правила области видимости

В этом примере expr2, *expr3, statement *заключены в неявный блок, который содержит блок локальных переменных, объявленных конструкцией let expr1 . Пример приведён выше.

Примеры

let vs var

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

let в циклах

Вы можете использовать ключевое слово let для привязки переменных к локальной области видимости цикла for , вместо того что бы использовать глобальные переменные (объявленные с помощью var ).

Нестандартизированные расширения let

let блок

Предупреждение: Поддержка let блоков была убрана в Gecko 44 баг 1023609.

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

Синтаксис
Описание

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

Пример

Правила для этого блока кода аналогичны как и для любого другого блока кода в JavaScript. Он может содержать свои локальные переменные, объявленные let .

Правила области видимости

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

let выражения

Предупреждение: Поддержка let выражений была убрана в Gecko 41 баг 1023609.

let выражение позволяет объявить переменные с областью видимости ограниченной одним выражением.

Синтаксис
Пример

Вы можете использовать let для объявления переменных, областью видимости которых является только одно выражение:

Чем различаются var, let и const в JavaScript

На практике разбираемся, чем различаются var, let и const и когда их использовать.

Иллюстрация: Катя Павловская для Skillbox Media

Евгений Кучерявый

Переменные в JavaScript можно создавать тремя способами — c помощью ключевых слов var, let и const. Они выполняют одну и ту же функцию (объявляют о создании именованной ячейки в памяти), но работают немного по-разному.

Содержание:

Объявление, инициализация и область видимости переменной в JavaScript

Перед тем как обсуждать отличия var, let и const, разберёмся с некоторыми базовыми понятиями.

Программы на JavaScript хранят числа, строки, логические значения и более сложные объекты в именованных ячейках памяти — переменных. Данные из этих ячеек можно применять в расчётах, выводить на экран и перезаписывать. К переменным обращаются по уникальному имени, или идентификатору.

Объявить переменную — значит ввести новый идентификатор в программу.

До выхода стандарта ECMAScript 6 переменные в JavaScript объявляли только с помощью ключевого слова var:

Когда интерпретатор JavaScript находит очередное объявление с var, он выделяет место в памяти и по умолчанию присваивает элементу значение undefined — то есть «неопределённое». Также undefined можно получить, если обратиться к несуществующим элементам массива и свойствам объекта.

Обращение к неопределённому значению может привести к непредсказуемым ошибкам, поэтому рекомендуется как можно раньше давать переменным начальное значение — то есть инициализировать их. Делается это с помощью оператора =:

Мы можем выводить переменную best_podcast на экран и перезаписывать её сколько угодно. Главное — чтобы в момент обращения программа её «видела». Да, в разные моменты времени переменные то скрываются, то появляются в поле зрения интерпретатора JavaScript.

Часть программы, в которой доступен тот или иной идентификатор, называют областью видимости переменной.

В зависимости от области видимости в JavaScript различают локальные (functional scope) и глобальные (global scope) переменные. Локальные создаются внутри функции и доступны только в её пределах. А глобальные объявляются вне функций и видны в любой точке программы. Именно в работе с областью видимости и заключаются различия между var и let.

Как работает var и что с ней не так

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

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

Это позволяет создавать переменные с одинаковыми названиями и обращаться к внешним переменным через специальный объект window:

Не стоит привыкать к var. Использование этого ключевого слова в 2022 году считается плохой практикой по нескольким причинам.

Отсутствие блочной области видимости. Var-переменная, созданная в блоке if‑else или цикле, доступна за пределами своего блока. Например, в C++ или Java не получится получить доступ к счётчику цикла нигде, кроме тела этого цикла, а вот в JavaScript, если счётчик объявлен как var, — получится легко. Это практически всегда приводит к труднораспознаваемым логическим ошибкам.

Повторное объявление. Переменные var можно создавать повторно, и компилятор не будет ругаться. Почему это плохо? Допустим, в вашем JS-файле 4000 строк кода. Вы объявили на 5-й строке переменную books, которая хранит количество PDF-книг на сайте. А затем, добравшись до 3005-й строки, забыли об этом и создали другую переменную books — только теперь она хранит количество книг в корзине покупателя. Даже если вы уверены, что всегда сможете отличить одну переменную от другой, то программисты, которые будут работать с вашим кодом, точно не скажут вам спасибо.

«Поднятие» переменной, или hoisting. Все переменные var считаются объявленными перед запуском скрипта. При этом они остаются undefined до тех пор, пока не выполнится код инициализации.

Если запустить приведённый выше код, компилятор выведет название лучшего подкаста про IT. Но почему? Ведь мы инициализировали переменную до того, как её определили. По «нормальной» логике интерпретатор должен вернуть сообщение об ошибке, потому что блок if никогда не выполнится и переменная не будет определена. Но с var такие парадоксы — обычное дело.

В современном JS есть более однозначный и логичный способ определения переменных. Тем не менее вы не раз столкнётесь с var в легаси-коде, поэтому знать о нём полезно.

Как работает let и чем она отличается от var

Ключевое слово let лишено недостатков своего предшественника. Переменные, объявленные с его помощью, нельзя объявить повторно — программа выдаст ошибку. Let-переменные тоже «всплывают», но при попытке обратиться к ним до инициализации вы получите ошибку ReferenceError.

Но главное — такие переменные имеют блочную область видимости. А значит, они доступны только внутри того блока <>, в котором были созданы:

Вот как различается поведение счётчика цикла, если его создавать с помощью var и с помощью let:

//Переменная i доступна за пределами цикла

//Переменная i доступна только внутри цикла
//Попытка использовать её приведёт к ошибке

В остальном поведение этих переменных идентично.

Объявление констант с помощью оператора const

С помощью ключевого слова const создаются константы. Например, физические и математические величины.

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

Например, в них можно хранить объекты из DOM:

Также стоит отметить, что неизменяемым сохраняется сам объект, а не его поля:

Что касается областей видимости, то const ведёт себя как let — разницы между ними нет.

Обратите внимание: let и const являются частью стандарта ECMAScript 6, который поддерживается не всеми браузерами. Заранее ознакомьтесь с таблицей совместимости.

Заключение

В большинстве случаев достаточно использовать var, но иногда необходимо убедиться, что ваши данные в сохранности — их нельзя изменить извне или изменить в принципе. В этих случаях let и const незаменимы.

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

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