Привет, Хабр! Представляю вашему вниманию перевод статьи «On let vs const» автора Дэна Абрамова.

Мой предыдущий пост содержит такой параграф:

let vs const vs var: Обычно, все что вам нужно, — это let. Если вам нужно запретить перезаписывание переменной, вы можете использовать const. (Некоторые очень педантичны по этому поводу и предпочитают использовать const, когда бывает только одно назначение переменной).

Это утверждение оказалось очень спорным, на Twitter'e и Reddit'e сразу же начались жаркие обсуждения по этому поводу. Похоже наиболее популярное мнение (или по крайней мере, устно высказанное большинством) это то, что следует всегда использовать const и обращаться к let только при необходимости, что может быть обеспечено ESLint правилом prefer-const.

В этом посте я коротко перечислю все за и против, которые я встретил, и выскажу свое личное мнение по этому поводу.

Почему предпочитают const


  • Четкое правило: Это лишняя нагрузка для мозга, когда вам приходится каждый раз думать, использовать const или же лучше будет let. Правило «Всегда используй const, где это работает» освобождает вас от лишней мороки и оставляет эту задачу для линтера.
  • Переназначения могут стать причиной багов: В больших функциях бывает так, что вы можете не заметить, если переменная переназначится, и это может оказаться причиной багов. Особенно в замыканиях. Const дает вам уверенность в том, что вы всегда будете видеть одно и то же значение.
  • Понимание мутации: Те, кто только начинает изучать JavaScript, могут неправильно понять принцип работы const, думая что он предотвращает мутацию переменной. Важно понять разницу между мутацией переменной и ее переназначением. Использование const принуждает вас понять и противостоять этому различию на ранней стадии.
  • Бессмысленные переназначения: Иногда переназначение переменной не имеет смысла вообще. Например, в React Hooks, значения, которые вы получаете из хука — как useState — больше похожи на параметры. Они идут в одном направлении. Видя ошибку при их назначении, вы раньше узнаете о потоке данных React'а.
  • Преимущества исполнения: Есть также редкие заявления о том, что движок JavaScript'а может быстрее исполнять код, где используется const, так как знает, что переменная не может быть перезаписана.

Почему не предпочитают const


  • Const теряет свой смысл: Если мы везде будем использовать const, мы потеряем способность понимать, было ли это важно, чтобы что-то не было переназначено.
  • Конфуз с иммутабельностью: В каждой дискуссии, где говорят, что нужно всегда использовать const, находятся те, кто путается в вопросе иммутабельности. Это неудивительно, так как обе операции (объявление и переназначение) используют один оператор "=". В ответ на это обычно говорят, что просто нужно «учить язык». Однако контраргументы таковы, что если метод, который должен предотвращать ошибки начинающих, приводит в замешательство этих самых начинающих, то это не так уж и полезно. И, к сожалению, это не помогает предотвращать ошибки мутации, которые распространяются на модули и влияют на все.
  • Давление во избежание переобъявления: Сторонники «const-first» метода принуждают разработчиков не использовать let в переменных, объявленных в условии. Например, вы можете написать
    const a = cond ? b : c
    вместо if условия, даже если оба b и c ветки (объекты) сложные и давать им подробные имена затруднительно.
  • Переназначение не может быть причиной багов: Есть три главные составляющие, когда переназначение может быть причиной багов: область видимости слишком большая (как модульная или большой функции), когда значение это параметр (так как не ожидается что это будет равно чему-то еще, кроме того, что было передано), и когда переменная использована во вложенной функции. Тем не менее, во многих ситуациях, большинство переменных не соответствуют ни одному из этих случаев, а параметры и вовсе не могут быть обозначены как константы.
  • Нет никакого преимущества исполнения: Это мое мнение, что движок уже бывает предупрежден — какие переменные объявлены один раз, даже если вы используете var или let. Если мы будем и дальше утверждать, что const делает код производительнее, то мы с таким же успехом можем утверждать и то, что дополнительные проверки могут увеличивать время исполнения, чем уменьшать его. Серьезно, движки же умнее.

Мое мнение


Мне все равно.

Я могу использовать любое правило которое используют другие.

Если вам не все равно, используйте линтер, который автоматизирует проверку и исправление, меняя let на const, так что это не потратит ваше время в дальнейшем ревью кода.

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

Ссылка на оригинал статьи — On let vs const.

Комментарии (49)


  1. untilx
    05.01.2020 13:54
    +2

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


    1. fougasse
      05.01.2020 16:49

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


      1. untilx
        06.01.2020 11:28

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


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


  1. greabock
    05.01.2020 14:34
    +2

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


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


    1. justboris
      05.01.2020 15:02

      С константами типа 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.


      1. Jouretz
        05.01.2020 15:41
        -1

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


        1. justboris
          05.01.2020 15:46
          -1

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


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

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


          1. Jouretz
            05.01.2020 15:55

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


            1. justboris
              05.01.2020 16:34

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


              1. Jouretz
                05.01.2020 16:45

                Что одно, что другое врятли можно назвать константой? А то что поля объекта можно менять, это баг или фича? я не представляю в какой ситуации оно полезно.


                1. Alexmaru
                  05.01.2020 17:40

                  ссылка на объект user — константа, ты не можешь воткнуть туда любой другой объект. А user.id — это другой объект, на который ссылается user. И это уже объекту user решать, константа-ли его id.


                  Это не баг, не фича, это очевидность.


                  1. Jouretz
                    05.01.2020 18:03

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

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


                    1. Myateznik
                      05.01.2020 21:39
                      +2

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


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


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

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


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


                      1. MooNDeaR
                        06.01.2020 10:08
                        -1

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


                        1. Myateznik
                          06.01.2020 14:17
                          +1

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


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


                        1. Nimtar
                          06.01.2020 15:33

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


      1. Myateznik
        05.01.2020 21:28
        +2

        Самое правильное с моей точки зрения это правило 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'


        1. Aingis
          05.01.2020 21:53
          -1

          Правило не лучшее. Если, например, делается деструктуризация свойств из объекта, какое-то переписывается, а какое-то нет, то чтобы удовлетворить правило, надо раздувать код лишними объявлениями.


          Это ещё один довод против навязывания const, которое на самом деле и не имеет практической ценности.


          1. Myateznik
            05.01.2020 23:47
            +1

            Почему?


            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 (в частности по приватным полям).


            1. Aingis
              06.01.2020 12:26

              const { width } = options
              let { height } = options

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


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


              Const здесь по факту просто помощь защита ссылки на значение от нежелательных изменений

              Что значит «нежелательных»? Вы либо меняете, либо нет. Не знаете что пишете? Когда изменение станет желательным, окажется, что нужно много движений с той же деструктуризацией чтобы поменять.


              Const по сути так же в рантайме при попытки смены ссылки на значение не пропустит данное действие, а заодно выкинет исключение.

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


              1. Myateznik
                06.01.2020 13:58

                А теперь сделайте имена реально длины и вложенности (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 и всё, остальной код как работал так и будет работать. А если использовать хорошие инструменты, то они вообще сами эту работу выполнят.


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

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


                1. Aingis
                  06.01.2020 15:02
                  +1

                  Существенной разницы не увидел.

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


                  Это уже аргумент с натяжкой т.к. эти же тернарки можно писать и в let и в var.

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


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

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


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

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


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

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


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

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


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


                  1. Myateznik
                    06.01.2020 15:26

                    Сравните с вариантом, когда у вас одно объявление и — внезапно — нужен 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, однако опять таки никто не читает документацию, и следует правилу "в других же языках так, значит и тут так и по другому не может быть".


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


                  1. t_kanstantsin
                    06.01.2020 16:04

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

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


        1. Finesse
          06.01.2020 03:07
          -1

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


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


          1. Myateznik
            06.01.2020 14:00
            -1

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


    1. yea
      05.01.2020 16:05
      +1

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


      1. Lodin
        05.01.2020 16:14

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


        1. t_kanstantsin
          06.01.2020 16:09

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

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


      1. kahi4
        05.01.2020 16:16
        +1

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


        1. justboris
          05.01.2020 16:32
          +3

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


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


          1. kahi4
            05.01.2020 17:34

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


        1. Dolios
          05.01.2020 18:26
          +1

          1. Finesse
            06.01.2020 03:10

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


            1. Dolios
              06.01.2020 09:15

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


    1. justboris
      06.01.2020 22:21

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


  1. vvadzim
    05.01.2020 18:37
    +1

    Я использую let для указания того, что переменная где-то дальше точно переприсваивается, ну а const — что не переприсваивается.

    Мне это очень сильно упрощает чтение кода. Да, просматривать даже 10 строк функции или компонента на предмет определить, переприсвавается ли эта переменная, мне влом. Вот когда приспичит переприсвоить её, тогда и сниму const. Заодно в git в diff при review будет видно, что это не просто строчка с переприсваиванием добавилась, а добавилось именно первое переприсваивание, а до этого переприсваиваний не было. Для меня это часто весьма полезная информация.

    А вот то, что писавший хотел мне сказать, что он просто планирует в будущем эту переменную переприсваивать, это для меня абсолютно бесполезная информация. Меня интересует только и исключительно переприсваивается ли эта переменная в этой версии кода.

    Соответственно и линтер настраиваю — всё, что не переприсваивается, должно быть const.

    ИМХО))


  1. i360u
    05.01.2020 23:02

    Использование var, let или const, на мой взгляд, это не абстрактный вопрос идеологии или философии разработки. Они все работают по разному и должны использоваться согласно своему поведению. Я использую const когда нужна уверенность в том, что эта сущность будет вести себя как константа и вызовет исключение при попытке перезаписи. Для дополнительной защиты ссылочных типов, можно использовать Object.freeze. Использование let более благоприятно для сборки мусора, поэтому в моем коде чаще встречается именно let.


  1. Mellorn
    05.01.2020 23:10
    +1

    Я то думал холивары на тему «let vs const» себя уже исчерпали, а оно не ))


    1. Riim
      06.01.2020 14:12

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


  1. Dark_Scorpion
    05.01.2020 23:59
    +1

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


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


    • Для импорта модулей и пакетов: const
    • Для констант (PI, SECOND, etc) или магических чисел: const с обязательным верхним регистром
    • Для объектов или массивов без freeze(): let
    • Для объектов или массивов c freeze(): const с обязательным верхним регистром имени переменой, свойства в обычном стиле.
    • Для простых переменных в функции: let


  1. Taritsyn
    06.01.2020 10:55

    Не так давно Андрей Ситник поднимал эту тему: «Я использую в коде только let, а const оставляю для настоящих констант на верхнем уровне файла (типа const DAY = 24 * 60 * 60)…» (оригинальный пост в Твиттере).


  1. eirnym
    06.01.2020 14:07
    -1

    Есть простой вопрос, на который данная статья и большинство обсуждений не дают ответ: а что быстрее для JS?


    Тут мы сталкиваемся с движками V8(Chromium), V8(NodeJS), WebKit, Gecko, IE, Edge (до перехода на хромиум) и другие (малые), в которых могут быть свои особенности и тонкие настройки под капотом.


  1. Riim
    06.01.2020 14:18

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


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

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

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


    1. vvadzim
      08.01.2020 11:04

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

      Значительную часть времени я код читаю, а не пишу. И даже часто это не последняя версия кода, а некая точка в истории, к которой меня привел git bisect или иные неисповедимые пути.

      И в этот момент для меня совсем не важно, мечтал ли в тот момент автор, что в будущем эта переменная будет меняться. Потому что то будущее для меня, вероятно, уже в прошлом, и я могу заглянуть в последнюю версию и посмотреть (не захотелось пока ни разу). А вот что для меня важно — так это количество времени, которое я потрачу на раскопки. И вот здесь правило «используется let — обязаны быть переприсваивания» оказывается полезным, поскольку уменьшает количество времени в одном из аспектов изучения кода — а именно для определения того, переприсваивается ли далее переменная. Просто сам факт того, что ответ уже есть и не надо его искать, позволяет оставаться сосредоточенным на других вещах, не переключаться, и не перегружать стек в голове. В моей этот стек коротковат. В принципе, если бы гитхаб и все ide подсвечивали по-разному переменные, которые меняются и которые не меняются, этот вопрос для меня не стоял бы. Если бы да кабы.

      Повторюсь: правило «используется let — обязаны быть переприсваивания» уменьшает количество оплачиваемого времени при сопровождении кода.

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


      1. Riim
        08.01.2020 15:26

        Тут просто разные типы мышления. Любители повсеместного 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.


        1. Myateznik
          08.01.2020 15:41

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


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


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


          1. Riim
            08.01.2020 16:15

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


        1. Myateznik
          08.01.2020 15:41

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