Skip to content

Instantly share code, notes, and snippets.

@coproduto
Created March 24, 2022 14:59
Show Gist options
  • Save coproduto/ee80cdbc607f345ad71032ab167589fc to your computer and use it in GitHub Desktop.
Save coproduto/ee80cdbc607f345ad71032ab167589fc to your computer and use it in GitHub Desktop.
/* Qual a diferença entre 'var', 'let' e 'const'?
*
* Todas essas keywords servem para declarar variáveis, mas cada uma delas tem nuances diferentes.
* /
/* Cada bloco de código nesta página é independente e deve ser executado em um ambiente JS limpo,
* sem variáveis globais declaradas.
*
* Comentários de bloco separam diferentes blocos de código.
*/
/*** LET ***/
/* A keyword 'let' declara uma variável mutável com escopo léxico.
* O que significam todos esses termos técnicos?
*
* "Mutável" significa que podemos reatribuir o valor ao qual a variável se refere.
*/
(() => {
let x = 1;
console.log(x); // 1
x = 2;
console.log(x); // 2
})();
/* Ao atribuir à variável já declarada, mudamos o valor dela no escopo no qual ela foi declarada. */
/* "Escopo léxico" significa que, se a variável é declarada dentro de um bloco no código,
* ela é "visível" dentro do mesmo *bloco textual* no qual ela foi declarada, *após* a declaração dela.
*/
(() => {
console.log(x) // Uncaught ReferenceError: x is not defined
let x = 1;
console.log(x); // 1
})();
console.log(x); // Uncaught ReferenceError: x is not defined
/* Como o primeiro console.log está antes da declaração, ele gera um erro.
* Como o segundo está no mesmo bloco e após a declaração, ele funciona.
* Como o terceiro está fora do bloco, ele gera um erro.
*/
/*** CONST ***/
/* A keyword 'const' declara uma variável com escopo léxico, tal como 'let', mas
* A variável criada é *imutável*.
*/
(() => {
const x = 1;
x = 2; // Uncaught TypeError: invalid assignment to const 'x'
})();
/* Ao tentarmos reatribuir a variável para que ela se refira a outro valor, recebemos um erro. */
/* Quando uma variável é declarada como const, isso impede apenas a redefinição da associação
* nome-valor que a variável representa. Ou seja, valores *internos* ao valor podem ser mudados - pois a referência
* do valor que é armazenada na variável segue a mesma.
*/
(() => {
const x = [];
x[0] = 1;
console.log(x); // [ 1 ]
x = [1, 2, 3] // Uncaught TypeError: invalid assignment to const 'x'
})();
/* Perceba que o fato da variável ser const não nos impediu de mudar os valores internos ao array.
* Isso ocorre pois a restrição de imutabilidade se aplica apenas à associação nome-valor criada diretamente
* pela variável. A variável armazena uma referência ao array, e essa referência não muda quando os valores do
* array mudam, portanto, é possível alterar os valores do array.
*
* Pessoalmente, eu não gosto desse comportamento e convenciono que, se um array for ser mutado, ele deve ser
* declarado usando 'let', mas isso é uma questão de escolha pessoal.
*/
/*** Um parêntese sobre variáveis globais ***/
/* Se você atribui um binding sem declará-lo, isso cria uma variável global. */
(() => {
x = 1;
})();
console.log(x); // 1
/* Pressupondo que a variável x já não tenha sido declarada no escopo global, o código acima, ao ser
* executado, criará a variável global x com o valor 1.
* É necessário tomar cuidado com atribuições em JS para não declarar variáveis globais sem querer.
*/
/*** VAR ***/
/* Finalmente, vamos falar de var.
* Var declara uma variável mutável local, assim como let.
* A diferença de var é que var NÃO segue o escopo léxico.
*/
(() => {
var x = 1;
console.log(x); // 1
x = 2;
console.log(x); // 2
})();
/* O exemplo acima se comporta igual ao exemplo com let.
* Mas vamos olhar outro exemplo:
*/
(() => {
x = 1;
console.log(x); // 1
var x;
})();
console.log(x); // Uncaught ReferenceError: x is not defined
/* O que aconteceu? A linha 'x = 1' não deveria ter declarado uma variável global?
* Bom, sim. Só que a declaração 'var' passa por um processo chamado 'hoisting' -
* Declarações var dentro de um determinado escopo são tratadas como se tivessem sido
* feitas *no início* da função que contém aquele escopo. Isso significa que a declaração
* x = 1 no bloco acima tem seu significado alterado por uma linha que vem *depois dela*,
* o que é bem pouco intuitivo.
*/
/* Há outra diferença de comportamento: */
if (1 === 1) {
let x = 1;
console.log(x); // 1
}
console.log(x); // Uncaught ReferenceError: x is not defined
/* No exemplo acima, o 'let' permite que criemos uma variável escopada ao bloco if onde é declarada. */
if (1 === 1) {
var x = 1;
console.log(x); // 1
}
console.log(x); // 1
/* Já usando 'var', a variável é hoisted até o topo do escopo *de função* onde é declarada.
* Como no bloco acima não há escopo de função, a variável é declarada *globalmente*.
* Por esses motivos, não é recomendável usar 'var'.
*
* O ideal é usar 'const' por padrão e 'let' no caso de mutação ser necessária.
* Feedbacks? Dúvidas? Me mande no twitter.com/coproduto ;)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment