Created
March 24, 2022 14:59
-
-
Save coproduto/ee80cdbc607f345ad71032ab167589fc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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