Код
#статьи

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

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

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

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

Содержание:


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

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

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

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

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

var best_podcast

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

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

best_podcast = 'people and code';

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

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

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

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

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

var a = 10;

function func()
{
    //Переменная создана глобально, поэтому её можно использовать где угодно
    a = 50;
}
func();
//Будет выведено 50
console.log(a);

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

function func()
{
    var a = 10;
}

func();

//Выведет ошибку, потому что переменная a доступна только внутри функции func()
console.log(a);

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

var x = 50;

function func()
{
    var x = 10;

    //Будет выведено 10
    console.log(x);

    //Будет выведено 50
    console.log(window.x);
}

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

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

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

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

function showPodcast() 
{
    //Вызовем переменную перед её объявлением
    best_podcast = 'people and code';
    if(false)
    {
        var best_podcast;
    }
    console.log(best_podcast);
}

showPodcast();
//Ошибки не будет, браузер выведет undefined 

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

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

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

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

function showPodcast 
{
    //Вызовем переменную перед её объявлением
    console.log(best_podcast);
    let best_podcast = 'people and code';
}

showPodcast();
//Получим ошибку. Спасибо, машина!

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

let a = 5;

if(true)
{
    let b = 5;
}

//Будет выведено, потому что переменная a объявлена вне какого-либо блока и доступна глобально
console.log(a);

//Вызовет ошибку, потому что переменная b объявлена внутри блока if и доступна только в нём
console.log(b);

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

varlet
for(var i = 0; i < 5; i++) {}

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

console.log(i);
for(let i = 0; i < 5; i++) {}

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

console.log(i);

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

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

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

const Pi = 3.14;
const c = 299792458;
const g = 9.8;

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

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

const content = document.getElementById("content");

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

const obj =
{
    x: 1,
    y: 5,
    z: 12
};

//Возможно
obj.x = 5;

//Выдаст ошибку
obj = 1;

//Попытка задать другой объект тоже приведёт к ошибке
obj =
{
    x: 51,
    y: 12,
    z: 8
};

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

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

Заключение

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

Изучайте IT на практике — бесплатно

Курсы за 2990 0 р.

Я не знаю, с чего начать
Научитесь: Профессия Python-разработчик Узнать больше
Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована