Quanto devo usar 'let' vs 'const' no ES6?

214

Eu tenho escrito muito código ES6 para io.js recentemente. Não há muito código na natureza para aprender, por isso sinto que estou definindo minhas próprias convenções à medida que avanço.

A minha pergunta é sobre quando usar constvs let.

Eu tenho aplicado esta regra: Se possível, use const. Use apenas letse você souber que seu valor precisa mudar. (Você sempre pode voltar e alterar a constpara a letse, posteriormente, for necessário alterar seu valor.)

O principal motivo dessa regra é que é fácil aplicar de forma consistente. Não há áreas cinzentas.

O fato é que, quando aplico essa regra, na prática 95% das minhas declarações são const. E isso me parece estranho. Só estou usando letpara coisas como ium forloop ou ocasionalmente para coisas como totais acumulados de Fibonacci (que não surgem muito na vida real). Fiquei surpreso com isso - verifica-se que 95% das 'variáveis' no meu código ES5 até agora eram de valores que não variam. Mas ver consttodo o meu código parece errado de alguma forma.

Então, minha pergunta é: está tudo bem em usar consttanto? Eu realmente deveria estar fazendo coisas assim const foo = function () {...};?

Ou devo reservar constpara esse tipo de situação em que você está codificando um literal na parte superior de um módulo - o que você faz em maiúsculas, como const MARGIN_WIDTH = 410;?

callum
fonte
7
Suspeito que esta questão seja primariamente baseada em opiniões e, portanto, provavelmente seja encerrada, mas meus 2 centavos: Não há problema em usar constisso tanto.
Jhominal
15
function foo() {...}é melhor do que<anything> foo = function() {...}
#
12
@ OrangeDog Gostaria de ver sua explicação para isso, pois concluí precisamente o contrário. Há uma ressalva que function foo() {...}pode causar pequenas confusões durante a depuração, devido à elevação. Além disso, sua existência significa que temos duas construções que fazem a mesma coisa, mas uma delas funciona apenas em um contexto muito específico. (Você pode usar uma expressão de função em qualquer lugar em que uma expressão possa existir, mas você só pode usar uma declaração de função no nível da instrução.) Se você favorecer a brevidade, o problema pode ser apenas o fato de a sintaxe da expressão de função usar a palavra inteira function.
Keen
11
Rastreios de pilha têm o nome da função em vez de anon. O içamento é bom e vamos definir funções em uma ordem natural, sem ter que se preocupar com a indefinição.
OrangeDog
11
Esses são bons pontos a ter em mente, mas ainda não estou convencido. Depuradores modernos fazem um bom trabalho ao escolher o nome de exibição correto para sua função com base em qual símbolo você o atribui (se houver - se houver, você pode usar uma expressão de função nomeada). A declaração natural da ordem da função é altamente subjetiva. Pode ser razoável pensar que a ordem natural é começar por definir as peças básicas e depois definir as peças que as usam.
Keen

Respostas:

183

Minha resposta aqui não é específica para javascript.

Como regra geral, em qualquer idioma que me permita fazê-lo de maneira semi-fácil, eu diria que sempre use const / final / readonly / o que for chamado no seu idioma sempre que possível. O motivo é simples, é muito mais fácil argumentar sobre o código quando é óbvio o que pode mudar e o que não pode mudar. Além disso, em muitos idiomas, você pode obter suporte para ferramentas que informam que você está fazendo algo errado quando atribui acidentalmente a uma variável que declarou como const.

Voltar e alterar uma const para uma let é muito simples. E ficar const por padrão faz você pensar duas vezes antes de fazê-lo. E isso é, em muitos casos, uma coisa boa.

Quantos bugs você já viu que variáveis ​​envolvidas mudavam inesperadamente? Eu acho que muito. Eu sei que a maioria dos erros que eu vejo envolvem mudanças inesperadas de estado. Você não se livrará de todos esses bugs usando liberalmente const, mas se livrará de muitos deles!

Além disso, muitas linguagens funcionais têm variáveis ​​imutáveis, onde todas as variáveis ​​são const por padrão. Veja Erlang, por exemplo, ou F #. A codificação sem atribuição funciona perfeitamente nessas linguagens e é uma das muitas razões pelas quais as pessoas adoram a programação funcional. Há muito a aprender com essas linguagens sobre como gerenciar o estado para se tornar um programador melhor.

E tudo começa com ser extremamente liberal com const! ;) São apenas mais dois personagens para escrever em comparação com let, então vá em frente e consttodas as coisas!

wasatz
fonte
45
consté mais do que dois personagens let...
OrangeDog
72
Mas 5 caracteres a menos do que imutável.
Cerad 9/04
7
Isso parece muito com o uso valno Scala (que declara uma variável como imutável) e somente usando var(o equivalente mutável) quando não podemos usar val. Em outras palavras, declaramos variáveis ​​como imutáveis ​​por padrão e só introduzimos mutabilidade quando absolutamente precisamos delas (o que pode ser simplesmente porque a abordagem mutável é mais limpa).
Kat
7
Concordo com esta resposta, mas lembre-se de que as coisas não são tão óbvias ao trabalhar com coisas como objetos simples ou matrizes, pois suas propriedades podem mudar mesmo que tenham sido definidas com 'const'. Eu tinha pensado em 'const' trabalhando como object.freeze, mas esse não é o caso.
backdesk
2
@Cerad Você quis dizer “4 caracteres a menos” ou estou perdendo alguma piada aqui?
Mathias Bynens
57

Tenha cuidado, porque as constchaves do objeto são mutáveis.

A partir daqui: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

chaves de objeto não estão protegidas

considere este exemplo:

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

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

A mesma coisa para matrizes:

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

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

Eu ainda não decidi totalmente, mas estou pensando em usar constpara todos os não-array / não-objetos e usar letpara objetos / matrizes.

lax4mike
fonte
34
Verdadeiro, mas esperado IMO - o que é constante é a referência do objeto atribuída ao seu const. colors = numbersnão funcionará, como esperado. Se você deseja proteger as propriedades do seu objeto, você pode usar Object.freeze() developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Josef Engelfrost
16
Enganador. É imutável. Mas as propriedades reais do objeto não são.
Gaston Sanchez
11
+1 Sim, a referência é protegida, mas, em termos de pergunta , é muito tolo usar em casos como const moment = require('moment'), a menos que você seja o tipo de pessoa que está preocupada com o que alguém tentará fazer moment = dead.fish(() => pizza)mais tarde.
MaxWell 17/02
5
Talvez seja mais realista se preocupar moment = Date.now(). Mas, em qualquer caso, se o código assume uma invariante, não vejo nada de errado em aplicá-lo sempre que possível.
James M.
3
Ninguém disse que eles não eram imutáveis, no entanto. É um mal-entendido comum que o objetivo de const seja torná-lo imutável, quando é realmente garantir que o nome nunca faça referência a um objeto diferente daquele para o qual foi inicializado.
monokrome
25

Não se preocupe com isso. consté uma adição incrível ao JavaScript, e eu recomendo que você o use em todos os lugares em que faz sentido. Torna o código mais robusto.

Quando se trata de objetos, constprotegerá sua variável da reatribuição, mas se você precisar de objetos imutáveis, precisará do Object.freezemétodo, veja abaixo.

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

constprotegerá apenas da reatribuição e o freezemétodo protegerá todas as propriedades imediatas. Se você precisar que todas as propriedades aninhadas também sejam imutáveis, precisará recursivamente freezeelas.

clean_coding
fonte
14
Note que Object.freezeé superficial.
Mathias Bynens
@MathiasBynens Me deparei com este comentário e estou curioso para saber exatamente o que você quis dizer com ele. Você poderia por favor elaborar?
Cole Roberts
@ColeRoberts O conceito de imutabilidade superficial é quando a própria referência do objeto é imutável, mas as propriedades ainda podem ser alteradas. A palavra-chave const apenas cria imutabilidade superficial, portanto, você precisa usar o Object.freeze se todas as propriedades também devem ser imutáveis.
clean_coding
3
@ColeRoberts Significa que os valores do objeto dentro de um objeto congelado (ou seja, objetos aninhados) ainda podem ser alterados. Consulte mathiasbynens.be/notes/es6-const#immutable-values para obter mais informações.
Mathias Bynens
19

No meu ES6 constnão se trata de post de imutabilidade , explico o que constsignifica exatamente de acordo com as especificações.

Com base nesses fatos objetivos, aqui está minha preferência pessoal:

[...] faz sentido usar lete constcomo se segue no seu código ES6:

  • usar constpor padrão
  • use somente letse for necessária a religação (ou seja, qualquer forma de reatribuição)
  • ( varnão deve ser usado no ES6)

Por mais subjetivo que seja, é um fato que isso se aproxima mais da intenção da especificação.

As pessoas que usam letpor padrão geralmente tratam constvariáveis ​​como constantes (o que não são necessariamente por design!). Cada um na sua, mas prefiro usar as coisas para o propósito pretendido, e não para algum significado inventado que as pessoas atribuem a ela com base em um mal-entendido.

Usar constapenas para constantes é como usar o <aside>elemento HTML apenas para o conteúdo da barra lateral.

Mathias Bynens
fonte
2
Por que você nomearia algo constse não é constante?
nu everest
3
@nueverest Porque não consté para isso. Você leu o texto acima?
Mathias Bynens
2
@MathiasBynens Eu acho que o problema (apenas?) constÉ que ele é chamado const. É um nome idiota (em javascript) que confunde muitos desenvolvedores (todos?) Primeiro. A IMO seria melhor se tivesse constsido chamado let(especialmente porque leté mais curto, mas consté muito mais comum) e letchamado de outra coisa.
MrN00b
@MathiasBynens Entendi, mas por que chamar assim? Está criando uma enorme quantidade de confusão, como mostra esta página.
Jtr13 #
4

Minha abordagem pessoal, pensada para ajudar na legibilidade e compreensão do código:


leté apenas para variáveis ​​de vida curta, definidas em uma única linha e não alteradas depois. Geralmente aquelas variáveis ​​que existem apenas para diminuir a quantidade de digitação. Por exemplo:

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]
  ...
}

constpara todos os nomes conhecidos por serem constantes em todo o módulo. Não incluindo valores constantes locais. O valueexemplo acima, por exemplo, é constante em seu escopo e pode ser declarado com const, mas como existem muitas iterações e para cada uma existe um valor com o mesmo nome , "valor", que pode induzir o leitor a pensar que valueé sempre o mesmo. Módulos e funções são o melhor exemplo de constvariáveis:

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

varpor tudo que pode ou não ser variável. Os nomes que podem confundir as pessoas que leem o código, mesmo que sejam constantes localmente e não sejam adequados para let(ou seja, não foram preenchidos em uma simples declaração direta), são solicitados para serem declarados com var. Por exemplo:

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
}

Comentários adicionais e possíveis atualizações futuras aqui .

fiatjaf
fonte
10
esse segundo trecho de código parece uma arma.
Julian
1

O JavaScript é um pouco especial, pois as variáveis ​​podem ser funções e outras, mas considere em C #, Java ou outra linguagem semelhante ao estilo C:

const public void DoSomething()

A consté estranho, e isso é porque o método declarações em línguas não pode mudar, uma vez que está compilada em outra coisa, que é o que eles fazem, não importa o que (ignorando alguns hacks terríveis que podem existir).

Por que o JavaScript deve ser diferente? Portanto, não é compilado, mas isso não significa que devemos jogar fora a segurança que os compiladores podem fornecer. O uso da constpalavra - chave nos dá mais segurança, o que certamente levará a aplicações mais robustas.

Joe
fonte