Pull to refresh

Comments 49

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

Так же можно продолжить и дойти до "в конце-концов всё превратится в машинные коды".
Но код пишут, в первую очередь, для удобства его чтения/поддержки.

Ну, так далеко идти ни к чему, достаточно дойти до виртуальной машины JS. /sarcasm


А если серьёзно, то о том и разговор

Вообще не понял о чем материал… для меня всё просто:
Переменная — это переменная. И не важно меняю я ее значение в коде или нет. Сейчас я не хочу её менять, а завтра захочу.
А константа — это константа. Ее значение не зависит от того, что хочу я или еще кто-то. Оно просто есть. Как те самые ПИ, постоянная Эйлера, количество дней в неделе, количество градусов полного угла, и т.д. и т.п. Константы инвариативны по определению.


В общем, я не очень понимаю откуда путаница. И я даже не встречал сторонников "const-first" ни разу. Думается мне, что это довольно занимательные зверьки.

С константами типа API_KEY, NODE_ENV все понятно, они глобальные и обычно пишутся капсом.


Вопрос про локальные определения внутри функции


function processItems(id) {
   let items = fetchItems(id);
   for(let item of items) {
        doSomething(item)
   }
}

Вот здесь для item и items можно использовать как let так и const, и у людей на эту тему противоположные мнения. А у eslint на этот случай есть правило, prefer-const, чтобы переменные только с одниим присваиванием всегда использовали const.

diff константа|иммутабельная переменная
Почему в js оператор объявления иммутабельных переменных назван const это уже второй вопрос.

Какие иммутабельные переменные?


const user = {name: 'Foo'};
user.name = 'Bar';
console.log(user); // {name: 'Bar'}

очень даже мутабельные, если я правильно понял что вы имели в виду.

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

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

Что одно, что другое врятли можно назвать константой? А то что поля объекта можно менять, это баг или фича? я не представляю в какой ситуации оно полезно.
UFO landed and left these words here
function processItems(id) {
   const items = fetchItems(id);
   for(let item of items) {
        doSomething(item)
   }
}

Мне больше интересно насколько адекватно называть константой сущность которая меняется при каждом запуске функции, например.
Без холиваров и прочего, но мне как-то казалось что «константа» это просто имя для какой-то более-менее постоянной величины (G, PI, e etc.), которую можно «заинлайнить» например. А вот насколько правомерно называть константой переменную которую запретили изменять я не уверен.

Сравниваете не сравниваемое, если в const из ECMAScript хранить примитивы (которые по своей природе immutable), так же как вы это делаете в других языках с приведёнными величинами (G, PI, e, etc.), то отличий никаких эти константы полностью иммутабельны т.к. ссылка на них иммутабельна и значения-примитивы тоже иммутабельны.


Если же вы храните в const объект (мутабельный по умолчанию), то и получаете иммутабельную ссылку на мутабельный объект. Чтобы объект был иммутабельным нужно его залочить Object.freeze() (блокирует конкретный объект).


const immutableObject = Object.freeze({
    name: 'Alice',
    age: 25,
})

Данный пример полностью иммутабельный т.к. мы используем иммутабельную ссылку, на иммутабельный объект с иммутабельными значениями переменных.


Главное понимать, что var, let, const это всё переменные, которые в сущности являются просто ссылками на значения, соответственно ключевое слово влияет только на область видимости и мутабельность этой самой ссылки, но никак не значения.

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

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


В случае JS все переменные являются ссылками, даже на примитивы т.к. JS унаследовал у другого языка правило, что любое значение это объект, даже сам объект. Соответственно ключевое слово влияет только на эту ссылку, но никак не на значение (объект)

А в каких мейнстримных языках const делает иммутабельным весь объект, указатель на который мы пометили?

Самое правильное с моей точки зрения это правило prefer-const из eslint. Кратко и просто: Если переменную не перезаписываем, то const. Иначе let. Больше никаких рассуждений не нужно.


function processItems(id) {
   const items = fetchItems(id);
   for(const item of items) {
        doSomething(item)
   }
}

В данном случае обе переменные const т.к. мы их не меняем (изменение атрибута переменной item не относится к изменению переменной).


Если мы меняем хранимое значение, то let:


let counter = 0
counter++

const object = {
    name: 'Bob'
}
object.name = 'Alice'
UFO landed and left these words here

Почему?


const options = {
    width: 100,
    height: 200
}

const { width } = options
let { height } = options
height += width / 16 * 9
options.height = height

А вообще ключевое, всё-таки если вам надо менять ссылку на значение в переменной, делайте её let иначе const. Это и есть всё правило.


const options = {
    width: 100,
    height: 200
}

const { width } = options
let { height } = options
height += width / 16 * 9
options = { ...options, height }

Но не проще ли в подобном случае сразу делать так:


const options = {
    width: 100,
    height: 200
}

options.height += options.width / 16 * 9

Т.е. я не совсем понимаю ваш довод, лучше тогда сразу покажите пример, где такое может встретиться и как это будет выглядеть. А там уже следую prefer-const правилу покажу как оно будет выглядеть, если что-то можно поменять согласно правилу.


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


А вообще это всё в туже сторону, что и TypeScript. С одной стороны всем так нравится, что он запрещает выстрелить в ногу подсказывая, с другой стороны иногда такой уровень типизации наоборот мешает. Const по сути так же в рантайме при попытки смены ссылки на значение не пропустит данное действие, а заодно выкинет исключение.


Относительно последнего абзаца я кстати пробовал и TypeScript и Flow, а в итоге вернулся к чистому ECMAScript с документацией в комментариях по типу JSDoc/ESDoc. VSCode совершенно спокойно распознаёт эти комментарии и выдаёт всё те же подсказки по типам, что и с TypeScript. И в данной ситуации не требуется компилировать в JS/ES и нет проблем с идеологией как у TypeScript (в частности по приватным полям).

UFO landed and left these words here
А теперь сделайте имена реально длины и вложенности (settings.product.someParams) и добавьте ещё пару переменных, и вместо искусственного примера сразу увидите раздутие.

Хорошо, вот тот же отрывок с "реальной длинной":


const { width, title } = settings.product.someParams
let { height, aspect } = settings.product.someParams

Существенной разницы не увидел. А вообще если на данном этапе у вас начинаются проблемы, возможно вы делаете что-то не так, к примеру вам не нужно столько деструкторизаций.


А нужен let затем, зачем и в топике написано. Чтобы, например, не делать плохо читаемые вложенные тернарники, а нормально читаемые последовательные if'ы.

Это уже аргумент с натяжкой т.к. эти же тернарки можно писать и в let и в var. Это уже зависит от разработчика и его желаний сократить код. А вообще это вопрос умения применять тернарки, если правильно оформлять, то и вложенные не будет особых трудностей читать. И да конечно же везде, где можно обойтись без тернарок или сложность условий велика лучше и нужно использовать if.


Вообще исходный код должен быть читаемым, а то, что пойдёт в продукт уже будет обработано каким-нибудь Terser'ом.


Что значит «нежелательных»?

То и значит. Иногда сломать весь код можно и банальным случайным или намеренным изменением значения переменной. К примеру, вот ожидаете объект и выполняете запрос к полю foo.bar, а выше какой-нибудь "Вася" в каком-нибудь if'е на каком-нибудь условии без церемоний записал в ваш let foo значение null. По логике "Васи" всё верно т.к. foo в конечном итоге возвращается из функции.


Вы либо меняете, либо нет. Не знаете что пишете?

Я может и знаю, что пишу, а вот те кто будет потом поддерживать и дальше развивать код не знают этого.


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

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


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

Если вы не встречались, не значит, что проблемы нет. Я вот на практике видел такие ситуация. Это из той же оперы, когда вы начинаете использовать "приватные" поля и методы классов, по тому, что так быстрее получаете данные, а то, что упускаете/провоцируете сайд-эффекты и т.д. без разницы.

UFO landed and left these words here
Сравните с вариантом, когда у вас одно объявление и — внезапно — нужен let. Вроде же по-русски писал, одно с другим связать не можете?

Вы лучше сразу пример приведите, как я просил с самого начала. Если у вас одно объявление и внезапно понадобился let, сделайте новое в чём проблема?


Речь не о можно, а том, что в случае const нельзя иначе. Вы вообще обдумываете свои решения или идёте на поводу толпы?

Речь именно о можно и нужно. В случае с const можно иначе и это let. Вот серьёзно в каком месте не понятно моё краткое объяснение правила prefer-const? "Если вы не меняете ссылку на значение — const иначе let". Где явно случай с вашим тернарным const лучше реализовать через let и с нормальными if. Это правило обращаю внимание не противоречит тому, что вы "пытаетесь донести" не вникнув в то, что я вам писал изначально. Вот для начала сами по обдумывайте то о чём говорит собеседник.


В первую очередь вы не обдумываете свои решения и ответы, особенно когда пишите про "идёте на поводу толпы". Какой нафиг толпы? Я опробовал prefer-const подход, он показал свои плюсы, я использую его.


И уж тем более я не "иду на поводу толпы" т.к. эта самая толпа категорически против приватных полей у классов в JS с текущим синтаксисом #fieldName. Я же в этом синтаксисе вижу плюсы: 1. хард приватность, а не "соглашение о приватности", нарушается постоянно; 2. сразу синтаксис показывает, что это приватное поле и не нужно вносить опять таки "соглашение по именованию приватных полей". Тут всё принёс язык и это хорошо.


Просто? Разговор с того и начался, что prefer-const не даст вам просто поменять, потому что при деструктуризации останутся незименные переменные.

Просто и про останутся неизменные переменные, ну и пускай останутся. Чем это мешает вам? Вот серьёзно это такая придирка ну серьёзно с натяжкой. Я просто вынесу из const необходимую/мые переменные в let и всё, если это одна, то можно вообще даже в let не пихать если задуматься.


Скорее всего, это симптомы плохого интерфейса и плохих практик. Такой код быстро зарубят на код-ревью.

К сожалению это всё случается и нет такой код не рубят на код-ревью ибо ключевое тут, что применяются данные практики чаще всего к стороннему коду.


Впрочем, вы даже на русском неаккуратно пишите.

Ну и как обычно, что в прочем не удивительно по "идёте на поводу у толпы" это попытка съехать на личности. Вероятно вы сами не менее плохо пишите код, с уверенностью в своей правоте.


P.S. Вдобавок, ниже уже привели ссылки на статьи, почему const не работает. Как верно подмечено, prefer-const заставляет использовать const, когда так совпало, что переменная не изменяется, а не только когда она реально должна быть константой.

Так я про тоже, чтобы использовать const когда переменная как ссылка на значение не изменяется т.к. все переменные в JS это ссылки. А вот про "должна быть константой" это от туда же "в других же языках", используйте соглашение по именованию капсом реальных констант.


Ну и теперь я пишу, что вы идёте на поводу у толпы, которая категорически не приемлет использование const в тех ситуациях, для которых и разрабатывалось это ключевое слово. Даже в proposal на эту фичу были примеры из ряда prefer-const, однако опять таки никто не читает документацию, и следует правилу "в других же языках так, значит и тут так и по другому не может быть".


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

Вроде же по-русски писал

Вместо высказывания своего "фе" и бросания обрывками фраз, которые понятны только одному человеку, есть замечательное решение: показать пример.
Иначе это выглядит как: "Ну тут есть какая-то проблема, у меня не получается самому сформулировать мысль. Поэтому догадайтесь сами. Я вот пятой точкой чую, что что-то не так, но доказать не могу".

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


Я не за правило «везде let», этот комментарий относится только к вашему аргументу. В своей практике я используют правило «const first» в большинстве случаев потому, что так заведено, но иногда намеренно для подстраховки от собственных ошибок (записи в переменную там, где не следует).

Возможно вы немного промахнулись и писали Aingis. Я же совершенно как и вы использую prefer-const.

Ну вот я сторонник const-first, и я, в свою очередь, не думал, что есть те, кто использует let тогда, когда не планирует переназначать ссылку (про константы с примитивными значениями не говорю, там ситуация простая). Это же просто инструмент, который в некоторых случаях спасет вас от выстрела себе в ногу. А в некоторых — например, непреднамеренное изменение полей констового объекта — не спасет. Но это всё ещё лучше, чем ничего. А какие могут быть минусы у такого подхода? Ну поменяете const на let, если нужно будет.

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

cлегка увеличивает конечный размер бандла

Я слышал, что недавно придумали "сжатие" статических файлов при передаче с сервера пользователю. Ещё не все браузеры и серверы поддерживают его, но перспективы впечатляют!:)

Я, будучи реакт разработчиком, следуя ориентированности реакта на функциональное программирование, вообще стараюсь писать в максимально функциональном стиле (включая эффекты из ocaml) и let использую супер редко частично из-за функциональной идеологии. Жалко только в js не так просто объявить переменную вообще иммутабельной, а не только запретить менять ссылку на объект, а в ts readonly прописывать у каждой переменной оверхед лютый

as const в typescript добавит readonly всем полям. Вот так:


const user = {name: 'Test'} as const

Хм, эту конструкцию я пропустил, спасибо за подсказку!

Он работает поверхностно. Для полной иммутабельности можно использовать deep-freeze.

По ссылке про это написано.

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

UFO landed and left these words here
Использование var, let или const, на мой взгляд, это не абстрактный вопрос идеологии или философии разработки. Они все работают по разному и должны использоваться согласно своему поведению. Я использую const когда нужна уверенность в том, что эта сущность будет вести себя как константа и вызовет исключение при попытке перезаписи. Для дополнительной защиты ссылочных типов, можно использовать Object.freeze. Использование let более благоприятно для сборки мусора, поэтому в моем коде чаще встречается именно let.
Я то думал холивары на тему «let vs const» себя уже исчерпали, а оно не ))

Всё только начинается)

Недавно с коллегой обсуждали подобное. Как не крути const это тактический уровень (модуль / класс / пакет), а не оперативный (функции). И получается что ставя её везде, мы никак себе не помогаем, (не разу не встречал случайное переопределение переменной в функции на 10-20 строчек) но и обманываем себя. Для массивов и объектов это не защищает от изменения значений, только от изменения ссылки (если не использован .freeze() ), а значит вводит в заблуждения при быстром чтении кода джунами и мидлами.


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


  • Для импорта модулей и пакетов: const
  • Для констант (PI, SECOND, etc) или магических чисел: const с обязательным верхним регистром
  • Для объектов или массивов без freeze(): let
  • Для объектов или массивов c freeze(): const с обязательным верхним регистром имени переменой, свойства в обычном стиле.
  • Для простых переменных в функции: let
Не так давно Андрей Ситник поднимал эту тему: «Я использую в коде только let, а const оставляю для настоящих констант на верхнем уровне файла (типа const DAY = 24 * 60 * 60)…» (оригинальный пост в Твиттере).
UFO landed and left these words here

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


Действительно ли вы хотели сообщить, что ответ никогда не должен меняться, или просто так совпало, что вы нигде его не меняли?

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

Бывает множество привязок, которые нам ни разу не доводится изменять, но против изменения которых мы ничуть не возражаем. На деле, пожалуй, это справедливо для большинства ссылочных переменных. Это не главное, что обычно заботит ваш код.
UFO landed and left these words here

Тут просто разные типы мышления. Любители повсеместного const используют его для заявления фактической константности, а любители повсеместного let, для заявления идеологической константности. Одним больше помогает одно, другим другое. Большинство исходных утверждений от которых вы отталкиваетесь и делаете какие-то выводы ложны для меня. Вот например:


Просто сам факт того, что ответ уже есть и не надо его искать

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


Ещё один уже объективно ложный аргумент любителей const (вы его не приводили, но он уже есть выше нашего разговора), это то, что используя let можно выстрелить себе в ногу. Если у вас let тоже стреляет (или стрелял и вы перешли на const), то вы пишете кривой код. Без обид)). Смотрите как это происходит:


class SomeView {
  onBtnClick() {
    let btn = this.$('btn');
    btn.disable();
    getSomeData().then(res => {
      btn.enable();
      // ...
    });

    // Здесь другой программист решил ещё логики добавить заиспользовав существующую переменную.
    // Он забыл учесть, что обрабатывающий запрос колбек ещё не выполнен (может не заметил его не став подробно разбираться в коде, которого часто больше чем в примере), а когда будет выполнен, в нём окажется неправильная кнопка.
    btn = this.$('other-btn');
    // ...
  }
}

Только так стреляет let. Почему этот код кривой? Потому что нет возможности при наследовании переопределить код обрабатывающий запрос. Как минимум нужно переписать так:


class SomeView {
  ready() {
    this.btn1 = this.$('btn');
  }

  onBtnClick() {
    let btn = this.btn1;
    btn.disable();
    getSomeData().then(this.onSomeData.bind(this));

    // Здесь другой программист решил ещё логики добавить заиспользовав существующую переменную.
    // Всё у него будет норм)).
    btn = this.$('other-btn');
    // ...
  }

  onSomeData(res) {
    this.btn1.enable();
    // ...
  }
}

И вот let уже никуда не стреляет и так во всех подобных случаях.


Если же есть желание написать именно с использованием колбека, то опять же let выигрывает, потому что его просто не будет: программист использующий осознанный const и знающий о ловушке обязательно сделает эту переменную константой предупредив коллегу в будущем. У него просто есть такая возможность, ведь в проекте с осознанным использованием const эти const просто так не расставляются. Другой программист увидев const задумается зачем он здесь и заметит колбек. При бездумном const этого не происходит: в 99.9% случаев замена const на let ничего не ломает и программисты настолько к этому привыкают, что совершенно перестают задумываться о такой ловушке. Const бездумно меняется на let, колбек не замечается и здрасте новый баг. И такой баг я не раз чинил в проектах с бездумным const.
Вот и получается, что в реальности, при грамотном коде, стреляет именно const, а не let.

Я немного обобщу, в общем и целом проблемы в выборе let и const нет, минус названный вами в сторону const вами же отображен и на let. Описанный подход prefer-const и вами prefer-let по своей сути идентичны +- (просто инверсия). 99.9% замена const на let ничего не ломает и эти же проценты переиспользование let тоже, однако всегда есть 0.1% когда это приводит к багам.


Соответственно стреляет не let и не const (шансы у них примерно равны), а непосредственно разработчики, которые либо невнимательны, либо безответственны, а иногда и то и другое.


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

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

Случайный дубль комента по двойному клику. Хабр стоит переводить кнопку в disabled по первому клику.

Sign up to leave a comment.

Articles