Frontender Magazine

ES6 const: иммутабельность ни при чём

Похоже, это весьма распространённое заблуждение, которое не исчезнет просто так. Я натыкаюсь на него в блогах, twitter-обсуждениях и даже книгах. Эта статья — моя попытка расставить все точки над i.

const создаёт неизменяемую связь

Ключевое слово const не означает, что значение является «константой» или что оно иммутабельно (неизменяемо). const-значение определённо может изменяться. Следующий пример выполнится без ошибок — это абсолютно валидный ES6-код:

const foo = {};
foo.bar = 42;
console.log(foo.bar);
// → 42

Единственная действительно иммутабельная вещь в этом примере — связь между именем переменной и её значением. const присваивает значение {} переменной foo и гарантирует, что этой переменной больше не будет присвоено никаких других значений. Последующее использование операторов присваивания, а также унарных или постфиксных -- и ++ вместе с этой переменной вызовет исключение TypeError:

const foo = 27;
// Любая из следующих незакомментированных строк вызовет исключение.
// Операторы присваивания:
foo = 42;
foo *= 42;
foo /= 42;
foo %= 42;
foo += 42;
foo -= 42;
foo <<= 0b101010;
foo >>= 0b101010;
foo >>>= 0b101010;
foo &= 0b101010;
foo ^= 0b101010;
foo |= 0b101010;
// Унарные операторы `--` и `++`:
--foo;
++foo;
// Постфиксы `--` и `++`:
foo--;
foo++;

ES6 const не имеет ничего общего с иммутабельностью значений переменных.

И как тогда сделать значение иммутабельным?

Примитивы (числа, строки, логические значения, символы, а также null и undefined) всегда иммутабельны.

var foo = 27;
foo.bar = 42;
console.log(foo.bar)
// → undefined

Чтобы сделать иммутабельным объект, используйте Object.freeze(). Этот метод существует ещё со времён ES5 и хорошо поддерживается браузерами.

const foo = Object.freeze({
  'bar': 27
});
foo.bar = 42; // выбрасывает исключение TypeError в строгом режиме;
              // просто не работает в обычном режиме
console.log(foo.bar);
// → 27

Обратите внимание на то, что Object.freeze() не поддерживает «глубокой заморозки» — свойства–объекты замороженного объекта всё ещё могут меняться. В статье на MDN об Object.freeze() приводится пример реализации функции deepFreeze(), делающей объект полностью иммутабельным.

Возможно, иммутабельные структуры данных появятся в будущих версиях ECMAScript — такое предложение уже было внесено.

const vs. let

Единственное отличие const от let состоит в том, что const предотвращает повторное присваивание какого-либо значения.

Всё, что написано до этого предложения — факты. Всё написанное после него — моё субъективное мнение, но отнеситесь к нему с терпением.

Учитывая вышесказанное, const делает код более читабельным: в своей области видимости const-переменная всегда ссылается на один и тот же объект. В случае с let-переменными такой уверенности быть уже не может. Поэтому будет разумно использовать let и const так:

Согласны ли вы? Почему (нет)? Мне особенно интересно мнение разработчиков, предпочитающих в первую очередь использовать let (даже если значение присваивается переменной только один раз). Почему вы предпочитаете использовать let вместо const? Это из-за заблуждения «const для констант» или по другой причине? Напишите в комментариях!

Если вы заметили ошибку, вы всегда можете отредактировать статью, создать issue или просто написать об этом Антону Немцеву в skype ravencry.

Mathias Bynens
Автор:
Mathias Bynens
GitHub:
mathiasbynens
Twitter:
@mathias
Сaйт:
https://mathiasbynens.be/
Андрей Романов
Переводчик:
Андрей Романов
Сaйт:
http://andrew-r.ru/
GitHub:
andrew--r
ВКонтакте:
http://vk.com/andrew_r

Комментарии (7 комментариев, если быть точным)

Автар пользователя
IvanovPvl

В let 3 символа, против 5 в const.

Автар пользователя
SilentImp

@halyc0n Я думаю что количество символов это не то, что должно влиять на выбор между let и const ;)

Автар пользователя
alvik48

Полностью согласен с выводом. Всегда по умолчанию использую const, если переменная не переприсваивается, иначе - let.

Автар пользователя
b1rdex

Javascript const === Java final. Использую const/final, если возможно.

Не по теме: зачем такие разрешения при попытке комментирования через сайт? Для аутентификации по-моему достаточно email в read-only.

image

Автар пользователя
jt3k

Разрешите немножко потроллировать:

``` let isValid = !!value; if (isValid){ /.../ }

const isValid = !!value; if (isValid){ /.../ } ```

Во втором случае имя переменной не выстраивается в один столбик и это дополнительно напрягает глаз когда читаешь чужое ))

Млн в предпросмотре листинг минифицированый. Надеюсь после запосщивания оно починится

Автар пользователя
SilentImp

@b1rdex комментарии сделаны как issue репозитория. Вероятно поэтому мне пришла в голову эта светлая мысль. Писалось всё три года назад и большую часть кода надо выбросить и переписать с нуля. В свободное время я над этим работаю.

Автар пользователя
b1rdex

@SilentImp запрашиваются разрешения на полный доступ к публичным репозиториям пользователя, а не FrontenderMagazine. Про issues=комментарии я понял. Когда не захотел давать такой доступ пришёл и на github сделал комментарий :) поэтому и получилось картинку вставить.