Сколько я должен использовать 'let' против 'const' в ES6?

214

Недавно я написал много кода ES6 для io.js. В дикой природе не так уж много полезного, поэтому я чувствую, что по ходу дела определяю свои собственные соглашения.

Мой вопрос о том, когда использовать constпротив let.

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

Основная причина этого правила - его легко применять последовательно. Там нет серых зон.

Дело в том, что когда я применяю это правило, на практике это 95% моих заявлений const. И это выглядит странно для меня. Я использую только letдля таких вещей, как iв forцикле, или иногда для таких вещей, как накопленные итоги Фибоначчи (что не так уж и много в реальной жизни). Я был удивлен этим - оказывается, 95% «переменных» в моем коде ES5 на сегодняшний день были для значений, которые не меняются. Но, видя constвесь мой код, я чувствую что-то не так.

Итак, мой вопрос: нормально ли это использовать const? Должен ли я действительно делать такие вещи, как const foo = function () {...};?

Или я должен зарезервировать constдля тех ситуаций, когда вы жестко кодируете литерал в верхней части модуля - как вы делаете в полных заглавных буквах, как const MARGIN_WIDTH = 410;?

Каллум
источник
7
Я подозреваю, что этот вопрос, прежде всего, основан на мнении и, следовательно, скорее всего, будет закрыт, но мои 2 цента: это нормально, чтобы использовать constэто много.
jhominal
15
function foo() {...}лучше, чем<anything> foo = function() {...}
OrangeDog
12
@OrangeDog Я хотел бы увидеть ваше объяснение этому, так как я пришел к выводу, что с точностью до наоборот. Существует предостережение, которое function foo() {...}может вызвать незначительную путаницу при отладке из-за подъема. Кроме того, его существование означает, что у нас есть две конструкции, которые делают одно и то же, но одна из них работает только в очень специфическом контексте. (Вы можете использовать выражение функции везде, где может существовать выражение, но вы можете использовать только объявление функции на уровне оператора.) Если вы предпочитаете краткость, проблема может заключаться просто в том, что синтаксис выражения функции использует целое слово function.
Сильно
11
Следы стека имеют название функции вместо anon. Подъем - это хорошо, и вы можете определять функции в естественном порядке, не беспокоясь о том, что foo не определено.
OrangeDog
1
Это хорошие моменты, чтобы иметь в виду, но я еще не убежден. Современные отладчики делают хорошую работу по выбору правильного отображаемого имени для вашей функции в зависимости от того, какой символ вы ей назначаете (если есть - если нет, вы можете использовать выражение именованной функции). Естественный порядок объявления функций очень субъективен. Возможно, было бы разумно подумать, что естественный порядок должен начинаться с определения основных частей, а затем позже определять части, которые их используют.
Кин

Ответы:

183

Мой ответ здесь не зависит от javascript.

Как правило, на любом языке, который позволяет мне делать это в полулегком виде, я бы сказал, всегда используйте const / final / readonly / независимо от того, как это называется в вашем языке, когда это возможно. Причина проста, гораздо проще рассуждать о коде, когда он абсолютно очевиден, что может измениться, а что нет. И в дополнение к этому, во многих языках вы можете получить поддержку инструментов, которая говорит вам, что вы делаете что-то неправильно, когда вы случайно назначаете переменную, которую вы объявили как const.

Вернуться назад и изменить const на let очень просто. И если по умолчанию использовать const, вам придется дважды подумать, прежде чем делать это. И это во многих случаях хорошо.

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

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

И все начинается с того, чтобы быть чрезвычайно либеральным с const! ;) Это всего лишь два символа, которые нужно написать, по сравнению с let, так что давай, и constвсе!

wasatz
источник
45
constна два персонажа больше, чем let...
OrangeDog
72
Но 5 символов менее неизменны.
Cerad
7
Это похоже на использование valв Scala (которая объявляет переменную неизменной) и использование только var(изменяемый эквивалент), когда мы не можем использовать val. Другими словами, мы объявляем переменные как неизменяемые по умолчанию и вводим изменчивость только тогда, когда она нам абсолютно необходима (что может быть просто потому, что изменяемый подход чище).
Кат
7
Я согласен с этим ответом, но имейте в виду, что вещи не так очевидны при работе с такими вещами, как простые объекты или массивы, поскольку их свойства могут измениться, даже если они были определены с помощью 'const'. Я думал, что const работает как object.freeze, но это не так.
backdesk
2
@Cerad Ты имеешь в виду «меньше 4 символов» или я здесь скучаю?
Матиас Биненс
57

Будьте осторожны, потому что constключи объектов изменчивы.

Отсюда: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

ключи объекта не защищены

рассмотрим этот пример:

const colors = {red: "#f00"}; 
console.log(colors); // { "red": "#f00" }

colors.red = "#00f";
colors.green = "#0f0";
console.log(colors); // { "red": "#00f", "green": "#0f0" }

То же самое для массивов:

const numbers = [1, 2, 3];
console.log(numbers); // [ 1, 2, 3 ]

numbers.push(4);
console.log(numbers); // [ 1, 2, 3, 4 ]

Я не решил полностью сам, но я рассматриваю использование constдля всех не массивов / не-объектов и использование letдля объектов / массивов.

lax4mike
источник
34
Верно, но ожидаемый IMO - то, что является константой, является ссылкой на объект, назначенный вам const. colors = numbersне будет работать, как ожидалось. Если вы хотите защитить свои свойства объекта, вы можете использовать Object.freeze() developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Йозеф Энгельфрост
16
Ложная. Это неизменно. Но реальных свойств объекта нет.
Гастон Санчес
1
+1 Да, ссылка защищена, но с точки зрения вопроса , это довольно глупо использовать в таких случаях, как const moment = require('moment'), если только вы не тот человек, который беспокоится о том, что кто-то попытается сделать moment = dead.fish(() => pizza)позже.
MaxWell
5
Возможно, более реалистично для беспокойства moment = Date.now(). Но в любом случае, если код принимает инвариант, я не вижу ничего плохого в его применении, где это возможно.
Джеймс М.
3
Никто не сказал, что они не были неизменными, хотя. Это распространенное заблуждение, что цель const состоит в том, чтобы сделать его неизменным, когда действительно нужно гарантировать, что имя никогда не будет ссылаться на объект, отличный от того, для которого оно было инициализировано.
монокром
25

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

Когда дело доходит до объектов, constзащитит вашу переменную от переназначения, но если вам нужны неизменяемые объекты, вам понадобится Object.freezeметод, см. Ниже.

const immutableOject = Object.freeze({immutableProperty: 'foo'});

constбудет защищать только от переназначения, а freezeметод будет защищать все непосредственные свойства. Если вам нужно, чтобы все вложенные свойства также были неизменяемыми, то вам нужно будет рекурсивно freezeих использовать.

clean_coding
источник
14
Обратите внимание, что Object.freezeэто мелко.
Матиас Биненс
@MathiasBynens Я наткнулся на этот комментарий, и мне любопытно, что именно вы имели в виду под этим. Не могли бы вы уточнить?
Коул Робертс
@ColeRoberts Концепция поверхностной неизменности заключается в том, что сама ссылка на объект неизменна, но свойства все еще можно изменить. Ключевое слово const обеспечивает только неизменность, поэтому вам нужно использовать Object.freeze, если все свойства также должны быть неизменяемыми.
clean_coding
3
@ColeRoberts Это означает, что значения объекта в замороженном объекте (т.е. вложенные объекты) все еще могут быть видоизменены. См. Mathiasbynens.be/notes/es6-const#immutable-values для получения дополнительной информации.
Матиас Биненс
19

В моем ES6 речь constидет не об неизменяемости поста, я объясняю, что constзначит именно по спецификации.

Исходя из этих объективных фактов, вот мое личное предпочтение:

[…] Имеет смысл использовать letи constв вашем коде ES6 следующее:

  • использовать constпо умолчанию
  • используйте только letесли требуется повторная привязка (т. е. любая форма переназначения)
  • ( varне следует использовать в ES6)

Как бы субъективно это ни было, факт, что это наиболее точно соответствует цели спецификации.

Люди, которые используют letпо умолчанию, обычно рассматривают constпеременные как константы (а это не обязательно, по замыслу!). Каждому свое, но я предпочитаю использовать вещи по прямому назначению, а не для какого-то придуманного значения, которое люди присваивают ему по недоразумению.

Использование constтолько для констант похоже на использование элемента HTML<aside> только для содержимого боковой панели.

Матиас Биненс
источник
2
Почему вы бы назвали что-то, constесли оно не является постоянным?
Ню Эверест
3
@nueverest Потому что это не то const, для чего. Вы читали выше?
Матиас Биненс,
2
@MathiasBynens Я думаю, что единственная проблема в constтом, что это называется const. Это глупое имя (в javascript), которое поначалу смущает многих (всех?) Разработчиков. ИМО лучше было бы, если constбы ему позвонили let(особенно потому, что letон короче, но constгораздо чаще) и letназвали бы что-то еще.
MrN00b
@MathiasBynens Я понимаю, но почему это так называется? Это создает огромное количество путаницы, как демонстрирует эта страница.
13
4

Мой личный подход, помогающий читаемости и пониманию кода:


letтолько для кратковременных переменных, определенных в одной строке и не изменяемых после. Как правило, те переменные, которые есть только для уменьшения количества набрав. Например:

for (let key in something) {
  /* we could use `something[key]` for this entire block,
     but it would be too much letters and not good for the
     fingers or the eyes, so we use a radically temporary variable
  */
  let value = something[key]
  ...
}

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

const PouchDB = require('pouchdb')
const instantiateDB = function () {}
const codes = {
  23: 'atc',
  43: 'qwx',
  77: 'oxi'
}

varза все, что может или не может быть переменной. Имена, которые могут запутать людей, читающих код, даже если они являются локальными константами и не подходят для let(т. Е. Они не заполнены в простой прямой декларации), применяются для объявления с помощью var. Например:

var output = '\n'
lines.forEach(line => {
  output += '  '
  output += line.trim()
  output += '\n'
})
output += '\n---'

for (let parent in parents) {
  var definitions = {}
  definitions.name = getName(parent)
  definitions.config = {}
  definitions.parent = parent
}

Дальнейшие комментарии и возможные будущие обновления здесь .

fiatjaf
источник
10
этот второй фрагмент кода выглядит как пистолет.
Джулиан
1

JavaScript немного особенный в том смысле, что переменные могут быть функциями и тому подобное, но рассмотрим в C #, Java или другом подобном языке стиля C:

const public void DoSomething()

Это constстранно, и это потому, что объявления методов в этих языках не могут измениться, как только они скомпилированы во что-то другое, это то, что они делают, несмотря ни на что (игнорируя некоторые ужасные хаки, которые могут существовать).

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

Джо
источник