Открыть список
Как стать автором
Обновить

Комментарии 76

Да ерунда же! Во всех зрелых и серьезных языках, которые лежат воснове остальных языков, с константами ассоциируются только те значения, которые реально являются константами, как например PI или строки
представляющие название событий. Зачем придумывать все заного для js и ломать устоявшиеся каноны? Иммутабельность, это совсем не константы, это стиль\архитектура.

Дело в том, что const — это не константа, а именно read-only переменная. Как правило, константам можно присваивать только скалярные значения, переменной же const в JS можно присвоить любой объект. Кроме того, const можно использовать и в циклах, если это перечисление. Например следующий код будет прекрасно работать:


const fruits = ["apple", "banana", "orange"];

for (const fruit of fruits) {
    console.log(fruit);
    // fruit = "dog" вызовет: TypeError: Assignment to constant variable.
}

Еще одна причина почему лучше везде где возможно использовать const, это интроспекция в IDE. Например, в TypeScript следующая проверка будет работать:


const eventHandler: Function | null = getHandler();

if (eventHandler === null) {
    return;
}
// с этого места eventHandler имеет тип Function

// ... много кода

// можно безопасно вызывать
// eventHandler - точно не null
eventHandler();

А если же заменить const eventHandler на let eventHandler, то код не скомпилируется, поскольку между первичной проверкой на null и вызовом eventHandler() мог присвоиться null уже где-то в другом месте.


Кстати, похожее декларирование переменных есть в Kotlin, только там используются ключевые слова var, val.
https://kotlinlang.org/docs/reference/basic-syntax.html#defining-variables

Дело не в том что можно присвоить, а что нет, дело в идеологии. Например, с точки зрения языка, имена для идентификаторов переменных можно задавать абсолютно любые, хоть в т_а_к_о_м кейсе. Но вы точно знаете, что наткнувшись на ПОДОБНЫЙ_КЕЙС имеете дело с константой. С той константой, что по логики приложения представляет неизменяемое значение. Замечу ещё раз что неизменяемая не по ходу выполнения программы, а по логике! Что значит по логике? Как уже сказал ранее, PI или значение типа для события, или же функция, возможно объект, который представляет из себя дефолтное значение какого-то конфига. Вот что такое константа с точки зрения программирования. Если помечать её все неизменяемые по ходу выполнения программы значения, то как тогда определить то, что явыше описал?

И Ваш пример с функцией просто идеально иллюстрирует то о чем я говорю. В то время как первый пример иллюстрирует иммутабельность.

Если вы про то, что ключевое слово const для определения read-only переменных было выбрано неудачно и вносит путаницу, то тут я полностью согласен.

А я — не согласен. Это просто ключевое слово, которое имеет свою семантику. Намного лучше val+var в некоторых языках, которые визуально очень похожи
Иммутабельность
Да, про иммутабельность там ни к селу, ни к городу. Видимо, автор хотел, чтобы из поисковика к нему приходили и на это слово.
А как ещё обозначить неизменяемость значения по ходу выполнения программы? Если readonly, то это непосредственно о конструкциях, а не о логике. К логике ближе понятие иммутабельности, хотя оно из области архитектуры стиля.
Во всей статье это слово встречается только раз, во вступлении и имеет мало отношения к тому, о чем речь пойдет дальше:
На протяжении этой статьи мы рассмотрим разницу между var, let и const, а также смежные темы такие как: “область видимости функции против блочной области видимости“, “поднятие” переменных и иммутабельность.
Абсолютно ненужная статья — материал по объявлению и инициализации переменных в современном JS за одну минуту гуглится любым новичком, который только начал изучать JS и сие гугление приносит over9000 ссылок и даже, прости Господи, видеоуроков по теме.
НЛО прилетело и опубликовало эту надпись здесь
Перевод какой-то деревянный… Про грамматику молчу тоже)

И так и не распарсил это… Что имелось ввиду?
> Следующие различие связано с “поднятием”. Ранее мы сказали, что определение “поднятия” это: “Интерпретатор JavaScript назначает объявленным переменным значение undefined во время фазы называемой “Создание”".

Воды больше чем в моем дипломе.


Предложу свой вариант: "всегда используйте const, кроме случаев когда не можете, тогда используйте let"

всегда используйте const, кроме случаев когда не можете, тогда используйте let

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


Цитата из этой статьи:


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

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

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

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


const a = 5; // точняк константа

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


Моё мнение — const по умолчанию хорош только при чисто функциональном стиле программирования. В остальных случаях лучше воспользоваться правилами из той же статьи:


1.Используйте const только в самой верхней области видимости
За всю жизнь не припомню случая, чтобы привязка, созданная внутри функции, расстроилась от своего изменения.

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

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


Кстати, вот вам привязка которая "расстраивается" от своего изменения:


const $element = $(...);
$element.on("foo", e => {
    $element.bar();
});
Ага, если бездумно менять код, то он сломается, const от этого не спасёт, ведь при повсеместном его использовании вы как обычно просто замените const на let и он точно так же сломается. А было бы использование const осмысленным, может это и помогло бы.

Если вы заменяете что-то в коде бездумно — не следует считать что все вокруг так же делают. const на let можно менять только после анализа всех мест использования.
const на let можно менять только после анализа всех мест использования.

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


не следует считать что все вокруг так же делают.

как вы делаете такие выводы? Вы блондинка? Окей, разжую, я имел ввиду, что при обдуманном изменении let-переменной действительно ничего не сломается.


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

Да, ничего не сломается если всё сделано правильно и это действительно была переменная, а не константа.

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

Так там как раз пример правильного использования const. Там константа и кто-то правильно запретил её менять. Вы привели пример к этому тексту:


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

Я его не писал и процитировал не как какой-то аргумент, а как часть правил при которых большинство констант обычно сами отмечаются правильно. Зря процитировал, сам не согласен с этим предложением, ну а вы нашли к чему придраться.

при обдуманном изменении let-переменной действительно ничего не сломается.
А типичная ошибка «пропустить один знак = в сравнении» — это обдуманное изменение? Мне кажется, использование const — лучше, чем постоянно писать Йода-сравнения.

У меня линтер заставляет обёртывать такое в дополнительные скобки:


if ((a = b)) {

это и при чтении кода помогает, сразу видно, что там что-то не совсем обычно. Можно настроить чтобы совсем не пропускал такое.

А в тернарке?
(a = b) ? 1 : 2;
vs
a == b ? 1 : 2;

Разве это не какое-то известное правило? Раньше, когда использовал javascript, у меня eslint подсвечивал такое заставляя добавлять скобки, причём я специально не настраивал это, то есть у многих должно работать как-то так же. Сейчас typescript как выяснилось не ругается, но при форматировании сам добавляет скобки. В данном случае добавил так:


let a = 5;
let b = 10;

console.log((a = b ? 1 : 2));
Уберите консоль.лог и поймете, что это вообще не универсальное решение.

let a = 5;
let b = 10;

var x = (a = b ? 1 : 2);


Или всё-таки так?
let a = 5;
let b = 10;

var x = (a == b ? 1 : 2);
Во втором случае typescript (или vscode) убрал лишние скобки.
А так?

let a = 5;
let b = 10;
let c = 10;

var x = a = b ? 1 : (a == c ? 2 : 3);

Сделал так:


let a = 5;
let b = 10;
let c = 10;

let x = (a = b ? 1 : a == c ? 2 : 3);
Как мило, адепты повсеместного const минусят также бездумно как и ставят const)). Уверен, большинство даже не пыталось осмыслить написанное.
Я не минусил, но прочитал и попытался осмыслить.

В целом вопрос написания const по дефолту мне напоминает холивар о написании классов final по дефолту. Суть идеи состоит в том, что класс для того чтобы его можно было эффективно наследовать должен быть заранее подготовлен к этому на этапе дизайна. Человек который пишет класс должен подумать о том как его будут наследовать и расширять. Если он об этом не думал (не было такой задачи) надо ставить final и такой класс не наследовать. Если понадобится то вернуться, передизайнить и убрать final.

Также и с const. Чтобы переменную можно было в любой момент брать и менять нужно заранее об этом подумать, чтобы нельзя было перевести приложение в некорректное состояние. Если программист об этом не подумал, следует объявить переменную const. Если кому-то понадобится её менять, пусть придет, подумает и поставит let.

Хорошее сравнение, судя по моему комменту ниже я заранее готовлю классы для наследования был бы против использования final по умолчанию.

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

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

Если вы не планируете её менять, зачем писать код с учетом этого? В 90% (оценочное суждение из головы) случаев никто ваш код трогать не будет никогда. В 9.5% случаев его удалят целиком не читая, и только в 0.5% случаев ваша работа проделанная для «подготовки переменной к последующему использованию» окажется полезна. А значит в 99.5% случаев вы делали лишнюю работу.

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

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


В 90% (оценочное суждение из головы) случаев никто ваш код трогать не будет никогда. В 9.5% случаев его удалят целиком не читая

у меня другой опыт: пишется один раз, дорабатывается 10 раз, читается 100 раз. Вы реально постоянно всё с нуля переписываете?

1. Кажется именно в этом месте происходит несовпадение взглядов. Мой поинт в том что если вы не предполагаете что вы или кто-то будет изменять эту переменную, то надо это запретить. Если вы разрешили то надо уделить этому внимание и подумать об этом. Но в большинстве случаев это не нужно и проще подумать об этом в тот момент когда необходимость возникнет. В этот момент у вас будет больше данных о том, что нужно сделать.

2. Да, честно говоря достаточно редко приходится точечно исправлять код (если это не багофикс). Такое что приходится прийти в какой-то метод и дописать пару строк не часто бывает. Чаще всего заменять какими-то блоками\компонентами, ну или как минимум функциями. При этом зачастую приходится провести какой-то нанорефакторинг в рамках которого исправить let на const или наоборот не составляет труда.

3. Чтение const упрощает значительно. Читая метод можно просто запомнить что в такой-то переменной лежит то-то и не думать об этом. Если переменная let то приходится держать в голове что там что-то может измениться.

Я в целом прекрасно вас понимаю, и некоторое время назад считал также как вы, но попробовал и проникся. Дело в том что вы относитесь к const как к чему-то особенному. Т.е. «по умолчанию переменные надо создавать как let, а const надо помечать только константы которые точно не должны меняться, выделять их таким образом» или что-то вроде того. А вы попробуйте применить этот подход на практике и увидите что почти все переменные в вашей программе можно объявить как const. И в этот момент произойдет сдвиг в сознании и осознание того факта, что на самом деле const это модификатор по умолчанию, и только редкие, единичные переменные должны быть помечены как let. И именно они должны привлекать внимание и вызывать настороженность, а не наоборот.

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

если что, то я уже больше 10 лет повседневно работаю с javascript/typescript и перепробовал очень многие вещи. Повсеместный const — одна из первых фич, которые я попробовал при появлении babel и навязал её использование не в одном проекте. Так что я то как раз полноценно с обоими вариантами поработал).
Такие вещи действительно нужно именно пробовать и порой достаточно длительное время, приведу хороший пример: первый рабочий день в новой компании, открываю код и, о ужас:


x == 1

Какое равенство нужно использовать в сравнениях, двойное или тройное? Уверен 99% смело ответят, что тройное, а оставшийся процент — неопределившиеся новички. Я тоже был исключительно за тройное. Спрашиваю — "Ребят, что за г в этом файле?", — "А у нас везде двойное равенство", — "Вроде компания серьёзная, а вы тут дикие какие-то. Вам Интернет отключили? Весь мир исключительно тройное использует!". Мне объяснили как нужно использовать двойное равенство не получая с этого стандартных минусов и в чём с этого будет плюс. И вроде понятно всё объяснили, там и объяснять то нечего, но я подумал: "ересь какая-то", говорю: — "Ну пофиг, буду делать как у вас тут принято, мне же не жениться на местном коде, но я остался при своём мнении", — "Окей, попробуй, посмотрим, что ты скажешь через пол года". Больше это не обсуждалось, но менее чем через пол года при рефакторинге личного кода я добровольно заменял тройное равенство на двойное. Тоже дикий совсем стал). До сих пор с удовольствием пользуюсь этой фичей в личных проектах, но ни разу даже не пытался где либо её пропихнуть, просто знаю, за такие мысли сразу камнями закидают, никто даже на секунду не задумается про попробовать, просто категоричное нет от всей команды. А там как раз была целая команда с удовольствием использующая эту фичу и как мне кажется большинство приходило в неё с теми же мыслями, что и я.


Та же ситуация с повсеместным const, все его используют, а тут какой-то вася какую-то ересь порет, и ладно бы объяснили и успокоился, но нет же, не унимается. Уже вон и в карму наплевали, действительно, да что вообще этот вася возомнил о себе!)). Мне вот как-то и в голову не приходило плевать в карму за отличающееся от моего мнение которое человек пытается спокойно обосновывать. Ну да пофиг, мне ж за карму на хабре не платят, хоть в минус загоняйте. Интересно другое: если завтра какой-нибудь фейсбук/гугл начнёт предлагать подобную ересь и использовать её у себя, то ситуация будет кардинально отличаться — нехотя, но начнут пробовать, а там глядишь и через пару лет станет общественным стандартом. Легчайше! Всего несколько лет назад кто бы мог подумать, что писать js, html и css в одном файле будет считаться нормой. Вот я бы такое предложил? Да сожгли бы!). Вот и получается победа общественного мнения и хайпа на собственным мозгом каждого.
Меня же та ситуация с двойным равенством научила спокойней относится ко всяким странным идеям, в каждом новом проекте я стараюсь попробовать что-нибудь новое, пусть и странное, хотя чаще это относится к каким-то архитектурным решениям, а не к такой мелочи, что мы здесь обсуждаем. Просто хотел показать альтернативный вариант, но, к сожалению, у многих это вызывает лишь желание меня заткнуть.

а потом сидите и гадайте

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

Есть там альтернативный смысл или нет, но кода может быть просто много:


const $element = $(...);

// много кода

$element.on("foo", e => {
    $element.bar();
});

// много кода

// а здесь вам стала интересна константа $element

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


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

но кода может быть просто много

Если кода много, то нужен рефакторинг.

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

Ведь const при его повсеместном использовании не значит ровно ничего.

Он значит неизменность ссылки. Это может быть полезно и, как минимум, не хуже let.

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

Вам придется оценивать ее «обдуманность», что сводит на нет пользу этих предположений.
Он значит неизменность ссылки. Это может быть полезно и, как минимум, не хуже let.

такая себе польза от знания того, что ссылка нигде не меняется, теряя при этом возможность знать от своего коллеги, что её нельзя менять по каким-то причинам. Ну не меняется она и что? Я для себя не нашёл пользы. Можете привести пример, в какой ситуации вам это что-то даёт?


Вам придется оценивать ее «обдуманность», что сводит на нет пользу этих предположений.

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

Если ссылка никогда не меняется — её безопасно использовать в любых замыканиях.

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

а так ли уж часто? Просмотрел сейчас несколько десятков файлов в текущем проекте, да, колбеки есть, но это всегда чистые функции ничего не использующие и не меняющие вне себя. Можно представить ситуацию вроде такой (абстрактный код):


class SomeView extends View {
  onBtnClick() {
    let btn = $('btn');
    btn.disable();
    request.get(...).then(res => {
      btn.enable();
      // ...
    });
  }
}

вроде замыкание, но такого в коде по-хорошему вообще не должно быть. Вот как мне теперь переопределить только обработку ответа при наследовании? Соответственно переписываем так:


class SomeView extends View {
  initialize() {
    this.btn = $('btn');
  }
  onBtnClick() {
    this.btn.disable();
    request.get(...).then(this.onResponse);
  }
  @autobind
  onResponse(res) {
    this.btn.enable();
    // ...
  }
}

Опа-на и нет замыкания)). Причём избавлялись от него не ради избавления от замыкания, а по совершенно другой причине и такая причина в ООП всегда находится.
Плюс есть async/await, то есть даже если точно не нужно выносить обработку в отдельный метод, то так:


class SomeView extends View {
  async onBtnClick() {
    let btn = $('btn');
    btn.disable();
    let res = await request.get(...);
    btn.enable();
    // ...
  }
}

В результате в примерно 35 просмотренных крупных файлов въюшек и стора я не увидел ни одного замыкания с не константой. В файлах сборки тоже не нашёл такого, в основном колбеки в виде чистых функций. Максимум встречаются замыкания с константами:


const gulp = require('gulp');

gulp.task('some-task', () => {
  return gulp. // ...

но это опять же к нашей ситуации не относится.
В результате


Если ссылка никогда не меняется — её безопасно использовать в любых замыканиях.

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


Моё мнение — const по умолчанию хорош только при чисто функциональном стиле программирования. В остальных случаях лучше воспользоваться правилами из той же статьи:

В любом случае это пока единственный хоть сколько-то весомый аргумент за повсеместный const из тех что пока прозвучали.

Моё мнение — const по умолчанию хорош только при чисто функциональном стиле программирования. В остальных случаях лучше воспользоваться правилами из той же статьи:

В любом случае это пока единственный хоть сколько-то весомый аргумент за повсеместный const из тех что пока прозвучали.

Сомнительно. Я вот больше в сторону ООП тяготею. Я там тоже редко нужно использовать не-конст. А уж анонимные функции — от и подавно. К примеру, на реакте я бы написал как-то так:

class MyComponent extends React.Component {
  render () {
    return <button onClick={this.activate} />;
  }
  activate = (e) => {
    // do
  }
}


То есть опять же — не через замыкание.
Ну как бы и я про тоже, что замыканий с не константами в ООП получается совсем мало. Или я неправильно вас понял?
Замыканий вообще мало, методы очень маленькие и потому нету никакого смысла не объявлять переменные не через const.

В тех редких случаях, когда в этом есть необходимость — лучше явно указать, что вот эта вот переменная — изменяется.
Вооот), замыканий исчезающе мало либо вообще нет, а значит что? Значит если взять любую переменную в любом методе, то перейдя в место после её последнего использования можно делать с ней всё что угодно, хоть слона туда засовывай, ничего гарантированно не сломается. Правильно? То есть на первый взгляд вообще пофигу let или const. Но не совсем, const при дальнейшей доработке кода будет постоянно заставлять заменять его на let бесполезно тратя наше время. Пользы же он будет давать ровно ноль. В результате приходим к варианту повсеместного использования только let, кроме самого верхнего уровня. То есть const где-то ещё совсем не должен встречаться, а если встречается, то скорей всего с кодом что-то не так.
Господи, в каждом предложении вашего сообщения написана глупость!

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

То есть на первый взгляд вообще пофигу let или const
Нет, с точки зрения ясности кода — не пофиг. Понимание, что переменная один раз получает значение и больше не изменяется — очень поможет поддержке.

дальнейшей доработке кода будет постоянно заставлять заменять его на let
Нет, не будет. Изменение переменных нужно крайне редко, потому слово «постоянно» не подходит и потому его лучше указать явно. А еще оно закладывается в момент объявления переменной, а не делается внезапно из старой константной переменной.

Пользы же он будет давать ровно ноль
Нет, не ноль.

В результате приходим к варианту повсеместного использования только let
Нет, не приходим.

То есть const где-то ещё совсем не должен встречаться
Нет, должен
Зачем?

для дальнейшей доработки кода.


На дальнейшее я могу ответить только в том же духе, но не хочу.

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

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

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

пример, в какой ситуации вам это что-то даёт

Вы по неосмотрительности не затрёте ссылку, которую коллега решил сделать неизменяемой (для этого даже не нужно смотреть на объявление). Вы будете уверены в том, что присваивание выполняется лишь раз или же наоборот — let укажет на переиспользуемую природу ссылки. Может, как триггер: «А не фигню ли я делаю? Зачем здесь пересоздавать/перезапрашивать объект?»
из легаси

ну в легаси всё что угодно может твориться, здесь сложно что-то оценивать.


не затрёте ссылку, которую коллега решил сделать неизменяемой

как не затру, вот я нахожусь в каком-то месте кода, вижу $element, вижу, что это константа, если const расставлялся осмысленно, то да, не затру, ведь мне явно сказано не трогать, а так я лишь знаю, что пока ещё не менялась и всё, скорей всего можно менять просто заменив const на let. Ладно, я проверю точно ли можно так делать, но вот что там делает коллега с его хотфиксом я не знаю. А дальше получаем:


из легаси
ну в легаси всё что угодно может твориться

Условностям здесь доверять нельзя. Перелопачивать будет слишком дорого, останется исключением из правил, которому системно никто не будет следовать.

ведь мне явно сказано не трогать

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

А дальше получаем: из легаси

Чтобы не получать разночтений с коллегой о том, кто что понял, как следует стайлгайду и прочее, как мне кажется, лучше не переизобретать смысл на соглашениях, а следовать примеру стандартной библиотеки JS и именовать трушные константы в верхнем регистре (SCREAMING_SNAKE_CASE).

Ага:


const PATH = require('path');
const FS = require('fs');
const GULP = require('gulp');
const GULP_DATA = require('gulp-data');
const NUNJUCKS_RENDER = require('gulp-nunjucks-render');
const { t as T } = require('@riim/gettext');

Как-то так себе получается.

Такие себе константы)
Если изменить любую в одном методе, то соседний может сломаться, с этой точки зрения вполне себе)
Это неймспейсы по сути, а не константы) А манкипатчинг — низя-низя.
В вашем примере (если заменить комментарии
// много кода
на хотябы одну строчку кода) уже 7 значимых строк кода (не считая пустые). Мне кажется не стоит писать методы в которых больше восьми, ну максимум десяти, значимых строк. Лучше выделять из них дочерние функции. А в небольшой функции и запутаться сложнее.
больше восьми, ну максимум десяти

маленькое у вас ограничение. Я обычно ограничиваю себя высотой небольшого (macbook) экрана, в этом случае уже не важно значимые строки или нет.

Я посмотрел сейчас, на экран 13" макбука влезает около 40 строк кода. Это очень много для одного метода, на мой взгляд. Но в целом это конечно же дело вкуса и договоренности в рамках команды.
А в тексте адекватный код?

function discountPrices (prices, discount) {
  let discounted = []

  for (let i = 0; i < prices.length; i++) {
    let discountedPrice = prices[i] * (1 - discount)
    let finalPrice = Math.round(discountedPrice * 100) / 100
    discounted.push(finalPrice)
  }

  console.log(i) // 3
  console.log(discountedPrice) // 150
  console.log(finalPrice) // 150

  return discounted
}

discountPrices([100, 200, 300], .5) // NOT OK: ReferenceError: i is not defined

Мы получили ReferenceError: i is not defined. Что говорит нам о том, что переменная, объявленная при помощи let, ограничена областью видимости блока, а не функции.

тут discountPrices — за пределами функции.
а i и finalPrice за пределами блока и комментом обозначены как выдающие значение, но объявлены через let в другом блоке

Разумеется, нет. Об этом написано сразу под ним в тексте.

Комментарии не нужно было копировать просто.

Я так понимаю, что автор просто в комментариях к коду показывал, что у этих переменных такое значение было бы, если бы не let

Замыкания в цикле — это анти-паттерн, который нужно избегать всеми силами. В остальном, в данном примере все корректно отработано.

Как бы let и const ради замыканий в цикле и делались.

В принципе да, вы правы, это считалось дурным кодом только с `var`. В таком случае код по ссылке выше полностью корректен.
НЛО прилетело и опубликовало эту надпись здесь
Так понятно, для чего, но совершенно неочевидно — как. Вот вы бы, например, угадали результат, который там получается?
Скопирую сюда:
let a = [];
for(let i = 0;i<4;i++){
  a.push(function(){
    return(i);
  });
  i++;
}
console.log(a.length);
console.log(a[0]());
console.log(a[1]());
Спойлер
2, 1, 3
Очень неочевидно, что i в «шапке» цикла и i в теле — это разные переменные с двумя копированиями значений на каждую итерацию.
Вас путает двойка в начале и слишком мало данных. Если посмотрите так, то понять значительно легче:

let a = [];
for(let i = 0;i<14; i++){
  a.push(function(){
    return(i);
  });
  i++;
}
console.log(a.map(x => x())); // [1, 3, 5, 7, 9, 11, 13]


Первая итерация — создался i, он равен нулю, добавили функцию с замыканием на i, увеличили i, теперь он равен 1

Вторая итерация, создан новый i, который равен старому, равен единице, увеличили на 1, теперь он равен 2, добавили функцию с замыканием на i, увеличили i, теперь он равен 3

Третья итерация ...
С чего вы взяли, что двойка меня путает? Я просто говорю, что это неочевидно, если не копать специально — в какой момент что создаётся, и что что-то вообще откуда-то куда-то каким-то именно образом копируется в какой-то момент каждой итерации.
P.S.
В качестве разминки
let arr = [];
for(let i = 0, i1 = 0, b = { a: 0}; i < 4; i++) {
  let c = {...b};
  arr.push(()=>[i++,b.a++,c.a++, i1++]);
  i1++;
}
console.log(arr.map(x => x().join(', ')));
console.log(arr.map(x => x().join(', ')));
Да нет, там всё-таки одна переменная на каждую итерацию, с одним копированием значения. Вот тут «просто» и «понятно» написано как оно работает: tc39.github.io/ecma262/#sec-forbodyevaluation
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.