const создаёт иммутабельную ссылку на объект, но это не значит, что значение нельзя будет изменить — нет, это значение может быть изменено. Следующий код не будет являться ошибкой:
const foo = {};
foo.bar = 42;
console.log(foo.bar);
// > 42
const arr = [0, 20, 30];
arr[0] = 10;
console.log(arr);
// > [10, 20, 30]
Единственная вещь, которая тут неизменяемая, это ссылка на объект. 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 ничего не делает с неизменяемостью данных.
Так как же тогда получить иммутабельное значение?
Примитивные типы данных, такие как numbers, strings, booleans, symbols, null, or 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 exception при условии использования strict mode;
console.log(foo.bar);
// > 27
Но помните, что Object.freeze() поверхностный, т.е. у замороженного объекта до сих пор останется возможность изменять вложенные объекты. На MDN есть пример глубокой заморозки, метод deepFreeze, который позволит сделать полностью иммутабельный объект.
Object.freeze() работает только с объектами ключ-значение, и в настоящее время нет возможности сделать иммутабельными такие объекты, как Date, Map или Set.
Тут есть предложение по неизменяемым данным для будущего стандарта ECMAScript.
const vs. let
Единственное различие между const и let в том, что const обещает — переприсвоения не произойдёт.
С учётом вышеизложенного, const делает код более читаемым. В пределах области видимости const всегда ссылается на тот же объект. Используя let такой гарантии нет. Поэтому следует придерживаться следующей практики:
- Если это возможно — всегда используйте const по умолчанию
- let используйте тогда, когда необходимо переприсвоение
- var не должен использоваться вообще
Комментарии (67)
Miklos
10.10.2016 12:32let не всплывает и выбросит исключение если обратиться к ещё не объявленной переменной.
Например, тут будет ошибка ReferenceError: can't access lexical declaration `app' before initialization:
let app = app || {};
Akuma
10.10.2016 12:52-6Проблема в том, что все эти let и const все равно превращаются в var каким-нибудь Babel-ом, т.к. ES6 сейчас поддерживают не все браузеры и реальный код, рассчитанный на широкие массы не будет настоящим ES6.
Поэтому все «let не всплывает» и «const не иммутабельный» должны сопровождаться указанием на то, что нужно использовать настоящий ES6. В остальных случаях никаких гарантий как бы и нет.MaxKorz
10.10.2016 13:06+1Почему это проблема? Babel ведь не бездумно превращает let/const в var.
Переопределение const и let отсекаются на этапе компиляции
let в замыканиях обрабатывается специальным образом
let в разных scope так же обрабатывается специальным образом
Поиграйтесь здесь goo.gl/ecuSgq
MaxKorz
10.10.2016 13:11+1И судя по
http://caniuse.com/#feat=const
http://caniuse.com/#feat=let
поддержка браузерами очень даже хорошаяAkuma
10.10.2016 16:27IE 9-10, к большому сожалению, все еще в ходу.
И честно гвооря не встречал еще сайтов на «чистом» ES6. Правда и не искал.
По поводу комментария выше. Да, действительно, я этого не учел, признаю. Babel довольно сносно обрабатывает подобные ситуации.MaxKorz
10.10.2016 18:00+2оффтопНе соглашусь
По данным liveinternet.ru за сентябрь:
IE11 — 2.3%
IE10 — 0.4%
IE8 — 0.3%
IE9 — 0.2%
По логике «IE9 все еще в ходу», нужно и про IE8 не забывать, т.к. он даже популярнее IE9.
Но по сути IE8-IE10 в сумме набирают 0.9%. Тот же UC Browser и Opera Mini в сумме имеют 2.8%, но на них все забивают
Конечно, если речь идет про какой-нибудь банк или гос. сайт, то на IE8-IE10 нельзя забивать,
но если речь про обычный сайт-визитку, лендинг или интернет магазин, то на IE уже давно можно забитьAkuma
10.10.2016 18:15-2Не соглашусь с вами. Общая статистика может сильно отличаться от статистики сайта.
Например у меня в магазине IE < 11 это почти 3%. А с 11-м больше 5%.
Немного конечно, но такие пользователи частенько выносят могз, если у них что-то не работает. Поэтому если можно относительно безболезненно их учесть — почему бы и нет.Delias
10.10.2016 18:19+2А сколько пользователей из этих 3% делают покупки, есть статистика? Как бы это не получилось что-то типа 3 заказа в год.
MaxKorz
10.10.2016 18:21Это все равно не повод не использовать связку es6+babel, т.к. код скомпилированный babel может работать вплоть до IE7. И babel осуществляет синтаксическую проверку кода — при сборке сразу отсеиваются глупые синтаксические и некоторые логические(такие как двойное объявление) ошибки, что повышает стабильность кода. А значит и в старом IE больше вероятности, что все заработает. Но при этом всё пишется на новом ES6 с классами и плюшками.
affka
10.10.2016 13:12А есть какие-то данные о скорости работы этих let/const, особенно в виде es5 кода по сравнению с var?
serf
10.10.2016 13:53особенно в виде es5 кода по сравнению с var?
очевидно в es5 let/const транслируется в var всегда
mayorovp
10.10.2016 19:43Очевидно, при трансляции добавляется еще и замыкание. Именно поэтому беспокоятся за скорость работы.
serf
10.10.2016 19:52+2Беспокоится не о чем, несолько дополнительных скоупов на скорость ресолвинга var переменной не особенно повлияют (hoisting). О скорости следует думать в более глабольшом машстабе, на этапе дизайна системы и имплементации логики.
YemSalat
11.10.2016 03:54Почему обязательно замыкание? Можно же просто переменную в нужное место вставить…
mayorovp
11.10.2016 06:45for (let i = 0; i<10; i++) setTimeout(() => console.log(i), 100*i);
Покажите, как этот код может быть написан на es5 без дополнительного замыкания.
YemSalat
11.10.2016 07:01Этот — никак. Только при чем тут именно этот код? Вы на es5 его без замыкания тоже не напишете.
Речь была о том что Бабель будет вставлять замыкания на каждый let/const, там где их раньше не было, что не верно.
Aingis
11.10.2016 12:46Вообще-то легко:
Многие почему-то забывают или не знают про третий аргументfor (let i = 0; i<10; i++) setTimeout(console.log, 100*i, i);
setTimeout
.mayorovp
11.10.2016 13:05Менять число аргументов, передаваемых в setTimeout — нельзя, потому что вы — компилятор. И не можете доказать, что setTimeout — это та самая функция из стандартной библиотеки.
PS в Chrome ваш код не будет работать. Первый аргумент должен быть
console.log.bind(console)
Aingis
11.10.2016 14:37Покажите, как этот код может быть написан на es5 без дополнительного замыкания.
Менять число аргументов, передаваемых в setTimeout — нельзя, потому что вы — компилятор.
WAT? Я немного умею в уме компилировать, но я не компилятор, уверяю вас.
PS в Chrome ваш код не будет работать.
Думаете, я не проверял? Прекрасно работает с недавних пор.mayorovp
11.10.2016 14:45Пожалуйста, читайте ветку обсуждения с начала.
Очевидно, при трансляции добавляется еще и замыкание. Именно поэтому беспокоятся за скорость работы.
Aingis
11.10.2016 15:44И причём здесь трансляция, когда я вам привёл чистый ES5 код? Уже забыли вопрос, на который получили ответ?
Firesword
10.10.2016 16:48+2babel преобразует const/let в банальные var без всяких дополнительных обёрток, если только это не ситуация, где действительно нужна блочная область видимости.
Так что в общем случае в виде es5 кода — разницы нет.VolCh
10.10.2016 19:18Всё зависит от набора плагинов. Современные браузеры понимают лет и конст нативно и плагины Бабеля для низ можно не ставить.
Riim
10.10.2016 17:40const не нравиться потому что при доработке уже написанного с ним кода нужно постоянно следить не пора ли какой-то let переделать в const, если не следить, объявления получаются неконсистентными. Отвлекает, а какого-то профита я так и не заметил. Наверно можно какой-нибудь линтер настроить, что бы он находил такие let-ы, но не видя профита я решил не заморачиваться и использовать везде let.
Delias
10.10.2016 17:43+2Не можно, а нужно.
prefer-constRiim
10.10.2016 17:52Ну мне видимо уже не нужно)) По сути профит const в том, что не получится написать
if (a = b)
вместоif (a == b)
, но вот такого как раз и не случается, так как любой линтер такое с пелёнок проверять умеет.Delias
10.10.2016 18:22+1Ваше дело — использовать всю силу языка или нет.
Riim
10.10.2016 18:44Так в чём сила const, если единственная причина его существования ломается о любой линтер? При этом есть минимум два минуса, один из которых я привёл выше (prefer-const решает его лишь частично).
swandir
10.10.2016 19:40+2Единственное различие между const и let в том, что const обещает — переприсвоения не произойдёт.
С учётом вышеизложенного, const делает код более читаемым.
То есть назначениеconst
в том, чтобы дать человеку, читающему код, сигнал, что переменная переприсвоена не будет. Аlet
, соответственно, сигнализирует о том, что переменная скорее всего будет переприсвоена, соответственно это что-то вроде счётчика или флага, который далее будет проверен, то есть нужно обратить на это внимание.А если вы используете иммутабельные структуры, где изменение данных всегда означает изменение ссылки на объект, то вместе с
const
получаете гарантию полной неизменяемости, и по ссылке, и по значению.
VolCh
11.10.2016 08:26+2Нужно всё писать в const по умолчанию и пять раз подумать прежде чем переделать в let. И сто пять — в var.
Riim
11.10.2016 13:31при доработке уже написанного с ним кода
Про то и речь, что везде const, только где надо let, и вот при дороботке кода один из let становиться неизменяемым и это вообще никак не видно, код продолжает отлично работать. Если не следить за этим, то получаем неконсистентные объявления, что меня как перфекциониста напрягает, если следить вручную, то на это уходит уже значимое время, вроде бы немного, но везде помаленьку и начинает реально напрягать постоянно на это отвлекаться. Если настроить prefer-const, как посоветовали выше, скорей всего будет заметно лучше, изредка прийдётся править замечания линтера и постоянно писать на два символа больше. Мелочи, но и плюсы тоже совсем незначительны. Для меня минусы перевесили, да и вообще, складывается впечатление, что большинство использует const не ради каких-то реально видимых для себя плюсов, а просто потому что это сейчас модно.
YemSalat
11.10.2016 23:04+1Чтобы такого не было — надо лучше планировать свой код. У меня лично такие ситуации не возникают, если я знаю что какое-то значение по сути своей изменяемое — я конечно буду изначально использовать для него `let`.
const позволяет вам создавать «read-only» переменные, по моему опыту ~80% всех объявляемых переменных никогда не меняются и по сути являются константами.Riim
12.10.2016 13:07-1Это уже другой подход, отличный от
нужно изначально писать везде только
const
, и по мере надобности добавлятьlet
его я не пробовал, но могу предположить, что постоянно задумываться будет ли переменная меняться мне нафик не надо, особенно если это не приносит мне какой-то пользы.
Большой комментарий чуть ниже тоже вам))YemSalat
13.10.2016 05:34+1Нет, подход тот же — называется «планирование» кода и архитектуры приложения. При таком подходе у вас нету необходимости постоянно менять и обновлять какие-то переменные.
Изначальная запись всего в `const` — «набивает руку» везде его использовать.
В моем первом комментарии не говорилось о том что const нужно везде писать бездумно, думать нужно всегда.Riim
13.10.2016 12:23-1думать нужно всегда
вопрос о чём думать и какую пользу это приносит, если у вас проекты той сложности, когда не хватает о чём думать и в новых возможностях языка вы ищите проблемы а не решения, то да const вам необходим. Мне же нужно меньше думать о всяком бесполезном и больше делать, const тут явно в минус.
VolCh
12.10.2016 07:23+1Ну это, по-моему, придирка из разряда неиспользуемых переменных. Типа зачем объявлять переменные, а потом следить вдруг они уже не используются.
Riim
12.10.2016 13:06+1Только в случае неиспользуемых переменных от этого нельзя совсем избавиться, а в случае с const можно.
Вот вы все тут набрасываете на мои аргументы против const, но никто толком не говорит зачем он ему пригодился? Единственный аргумент сразу не ломающийся о какой-нибудь линтер или ещё что-то привёл swandir :
С учётом вышеизложенного, const делает код более читаемым.
То есть назначение const в том, чтобы дать человеку, читающему код, сигнал, что переменная переприсвоена не будет. А let, соответственно, сигнализирует о том, что переменная скорее всего будет переприсвоена, соответственно это что-то вроде счётчика или флага, который далее будет проверен, то есть нужно обратить на это внимание.Но вот кто-то из вас пробовал проверить как это работает на практике? Я вот пробовал, именно этот аргумент ещё с год назад показался мне достаточно убедительным чтобы попробовать. И знаете как он работает? Вообще никак! Вот открываю я чуть ранее (не знаю, может надо было дольше ждать) написанный мною код с const, вижу переменную объявленную через const, ура, теперь я знаю, что она не будет меняться, но что мне это даёт? Зачем мне это знать? Это как-то помогает понять логику далее написанного кода? Я этого вообще не заметил, скорее наоборот, это абсолютно лишняя инфа, отвлекающая от сути. Приведите конкретный пример кода и давайте обсудим как программист читая его лучше понимает его суть за счёт использования в нём const? Это реально будет лучшим доказательством его полезности. Я пробовал иначе, взял готовый код написанный ещё на var-ах и начал переписывать его на const+let, я думал, что может используя const я найду какие-то хитрые баги, которые раньше не замечал и которые const автоматом пресекает. Но и этого не произошло. Все теоретические плюсы const которые можно найти в Интернете на практике либо не работают, либо вообще идут в минус. Мне намного интереснее было бы услышать в качестве аргументов за const не эту теоретическую копипасту с Интернета, а чей-то практический опыт, пусть и субъективный, что-то типа: чувак, вот я начал писать с const и я реально ощутил, что мне стало проще перечитывать свой ранее написанный код. Вот вы можете так сказать?
Кстати ещё один минус const вспомнил:
let a; let b; let c; let d;
намного красивей чем:
const a; let b; const c; let d;
Если же группировать несколько переменных в один const/let, то ещё хуже получается, приходиться либо постоянно разрывать группу, либо делать две группы и раскидывать переменные по ним, что приводит к тому, что две переменные, которые близки по сути и должны объявляться рядышком, оказываются далеко друг от друга.
Это мелочь конечно, но таких мелочей на практике вылазит довольно много, я просто довно всё это пробовал и сейчас постепенно по ходу разговора вспоминаю как это было.
mayorovp
12.10.2016 13:18+1Часто наблюдаю вот такую конструкцию в начале какого-нибудь метода в чужих файлах:
var $this = $(this), $container = $this.closest(".container"), $button = $container.find(".button")
Здесь замена
var
наconst
напрашивается.Riim
12.10.2016 13:26-1Ну ок, так всё таки, что это даст в сравнении с бездумным let везде? Зачем мне лишний раз задумываться выбирая const или let?
mayorovp
12.10.2016 13:35+1А думать и не надо. При написании подобного "пролога" с серией операций поиска по DOM надо просто всегда писать const.
Riim
12.10.2016 13:44-1Здесь действительно почти не надо, но лишний тик в голове всё же иногда происходит, есть более сложные случаи. Процитирую себя:
Приведите конкретный пример кода и давайте обсудим как программист читая его лучше понимает его суть за счёт использования в нём const?
Как знание о том, что $this не будет меняться помогает вам понять логику дальнейшего кода? И если этого не происходит, то нахрена спрашивается вы в него вцепились? Модно, ES6 и всё такое?
mayorovp
12.10.2016 13:47+2Как знание о том, что $this не будет меняться помогает вам понять логику дальнейшего кода? И если этого не происходит, то нахрена спрашивается вы в него вцепились? Модно, ES6 и всё такое?
Очень просто. Если в коде будет ошибка и я буду ее искать — мне не придется проверять гипотезу "а может, какой-то баран (возможно, даже я сам) изменил $this посреди метода"?
Riim
12.10.2016 13:56+2Ладно, звучит убедительнее)), у меня таких ошибок уже сто лет как не было, так что для меня не работает, но это субъективно, для кого то может вполне резонно на это расчитывать.
mayorovp
12.10.2016 14:06+1Это у вас их не было. А теперь на проект приходит новый программист и понеслось :)
Riim
12.10.2016 14:20+1Ну если у нового программиста часто будут такие проблемы, то с ним в принципе много проблем будет, const тут мало что изменит. В целом да, можно засчитать как небольшой плюс const)).
YemSalat
13.10.2016 05:40+1но никто толком не говорит зачем он ему пригодился
А зачем вообще нужны иммутабельные значения в программировании?
Вон Riim с хабра никогда их не использует и вроде все норм, код даже красивее выглядит, ровнее…
Если серьезно, то вот вам пример — я считываю какое-то значение из конфига, мне нужно чтобы оно не менялось внутри данного скоупа (в том числе чтобы те кто будет работать с этим кодом после меня не могли его изменить)
const currentState = config.currentState // теперь currentState гарантировано не может быть изменено.
Riim
13.10.2016 12:38-2то вот вам пример
да, чуть выше я признал это плюсом в некоторых ситуациях, а именно в командах состоящих из "какой-то баран". Может вам уже пора поговорить с ним, а то я смотрю он вам всем всю малину портит))
Вон Riim с хабра никогда их не использует и вроде все норм, код даже красивее выглядит, ровнее…
обажаю хабр, здесь всегда найдётся чудо которое в ситуации где можно спокойно сказать "да чувак, в твоих аргументах что-то есть и твой вариант похоже имеет право на жизнь" и на этом спокойно разойтись, будет до хрипоты в голосе усираться и доказывать, что нет!, только его вариант единственно правильный и никак иначе. А когда кончаться аргументы скатится на банальное язвление. Язвить я умею не хуже вашего, поэтому если больше нет интересных аргументов, то предлагаю не трахать друг другу мозг и на этом разойтись.
YemSalat
13.10.2016 13:15-1Да я ж не заставляю, не нравится — не используй на здоровье.
С опытом понимание само придет.Riim
13.10.2016 13:35-2не используй
не тыкайте мне, пожалуйста.
С опытом понимание само придет
вам как в соседней теме прислать резюме со списком проектов? Или может свой невероятный опыт в виде рабочих проектов продемонстрируете? А то все такие опытные пошли, куда деваться.
Ohar
13.10.2016 13:43-1я признал это плюсом в некоторых ситуациях, а именно в командах состоящих из "какой-то баран"
Команда всегда состоит из «какой-то баран», даже если программист там один. Потому что программисты — люди, а люди делают ошибки.
И использованиеconst
— лишний способ избежать ошибок.Riim
13.10.2016 14:03-2Команда всегда состоит из «какой-то баран»
у вас видимо всегда, ну ок, свои аргументы я привёл, с этим плюсом const тоже согласен, кому интересно почитают, взвесят и решат для себя (а ещё лучше попробуют). Что-то новое здесь уже вряд ли прозвучит, а препираться с теми кто принципиально не готов признавать альтернативы смысла нет, так что всем удачи.
YemSalat
11.10.2016 08:03+1Честно говоря мне кажется статья не уровня хабра.
Статья озаглавлена «ES6 const это не про иммутабельность» и в ней как раз таки рассказывается как работает 'иммутабельност' для const в ES6
То что иммутабелность не поддерживается для содержания объектов — так это часть стандарта и везде на это и так указано.
Мне кажется контент такого содержания больше подходит для tweet'a или каких-то микро-блогов.
VolCh
11.10.2016 08:39Const создаёт иммутабельную переменную (не константу!), значение которой нельзя изменить после инициализации. Всё в принципе. То, что в JS есть ссылочные (объектные) переменные никак этого не изменяет, равно как объявление const не меняет поведение объекта на которую эта переменная ссылается.
Какое-то непонимание «про что» const в JS может возникнуть в двух случаях:
1) непонимание чем отличаются константы, переменные и иммутабельные переменные вообще в программировании
2) незнание синтаксиса JS, предположение, что const — объявление константы, а не иммутабельной переменной
mickvav
Чем var хуже let, не понял…
Sergiy
scope-ами ессесно!
MaxKorz
имхо, польза let — в строгости — это как нативный jslint.
В простом JS такой код спокойно отработает и a станет массивом.
Если подключить JSLint, то вывалится ошибка Redefinition of 'a' from line 0.
А let исключает повторное объявление нативно, такой код
вывалится с ошибкой Uncaught SyntaxError: Identifier 'a' has already been declared
Код без повторного присваивания чище, легче читается и легче отлаживается.
А так же с let облегчается использование for циклов
sneakyfildy
http://stackoverflow.com/questions/762011/let-keyword-vs-var-keyword-in-javascript