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 для констант» или по другой причине? Напишите в комментариях!