No início dos meus estudos mais aprofundados em JavaScript, na disciplina de Desenvolvimento Web I, discernir entre os tipos de declarações de variáveis era, certamente, uma das minhas maiores dificuldades. Afinal de contas – e era assim mesmo que eu pensava –, não é tudo a mesma coisa?
Adivinha só: não é! E muito disso se baseia nos conceitos de escopo. Se em tempos remotos só tínhamos o var
como declaração de variáveis em escopos globais e de função, com a chegada do ECMAScript 6, lá em 2015, tornou-se possível declarar variáveis com let
e const
e também surgiram os escopos de bloco, funcionalidades que deixaram o JavaScript mais uniforme e (um pouco) menos sujeito a problemas de segurança.
🚨 ...e acho que aqui vale um pequeno adendo sobre o que é um escopo e quais os tipos de escopos que existem:
O escopo global se refere a todo o código – ou seja, se você tiver 20 funções diferentes no seu documento de código e declarar uma variável global, é possível utilizar essa variável nessas 20 funções. Assim:
var hello = "Bem-vindo!";
function visitorOne() {
alert(hello);
}
function visitorTwo() {
alert(hello);
}
function visitorThree() {
alert(hello);
}
alert(hello);
Já o escopo local (ou de função) é todo pedaço de código referente a uma função. Ou seja, uma variável de função é toda variável declarada dentro de uma função e que só pode ser acessada dentro dela. Um exemplo:
function showComments() {
let comment = "Muito legal!";
console.log(comment);
//Ao acessar essa função, o valor da variável "comment" será mostrado em tela.
}
showComments();
//Muito legal!
function showOtherComments() {
console.log(comment);
//Aqui o resultado retornado pela função hideComments será um erro dizendo que a variável não foi definida, pois é impossível acessar a variável "comment", já que é uma variável reservada APENAS ao escopo da função showComments(), logo, será interpretada como se fosse uma variável inexistente.
}
showOtherComments();
//ReferenceError: comment is not defined
Por fim, o escopo de bloco é qualquer região do código que utilize os famosos "bigodinhos" (ou melhor, chaves), assim como as funções, porém, a diferença esse tipo de escopo é criado por estruturas de controle, tais como as estruturas condicionais if/else
ou switch
, de repetição for
ou do/while
, entre outros. Por ter essa particularidade, as variáveis declaradas em escopo de bloco podem ser acessadas dentro de toda a função, e não apenas na estrutura de controle. Tipo isso aqui:
function commentPost() {
//Escopo de função
let blogPost = "finished";
if (blogPost === "finished") {
//Escopo de bloco
var username = "anewrites";
alert(`Comenta aí, ${username}! :P`);
} else {
alert("Continue lendo <3");
}
console.log(blogPost); //finished
console.log(username); //anewrites
}
Agora que já temos uma pequena noção de como cada tipo de escopo funciona, vamos dar uma olhada no que significa cada declaração de variável e como elas podem ser utilizadas dentro de cada tipo de escopo. 👇
O velho conhecido "var"
Como eu comentei ali no comecinho do post, o var
era a única declaração de variável global e de escopo de função disponível até a chegada do ES6 – ou seja, o var
pode ser declarado globalmente e ser acessado em qualquer região do código, ou ser declarado em escopos de função e acessado apenas nas funções as quais essas variáveis pertencem. Resumidamente, a vantagem de utilizar var
, pelo menos até a chegada do ES6, é diferenciar variável local de variável global.
//Sintaxe:
var varname1 = value1;
//Var declarada de forma global
var posts = 2;
function postCounter() {
console.log(posts);
}
function postCounter2() {
console.log(posts);
}
function postCounter3() {
console.log(posts);
}
postCounter(); //2
postCounter(); //2
postCounter(); //2
console.log(posts); //2
//Var declarada em escopo de função
var name = "Ane";
function postCounter() {
var numberOfPosts = 2;
console.log(`${name} fez ${numberOfPosts} posts até agora!`);
}
postCounter(); //Ane fez 2 posts até agora!
console.log(numberOfPosts); //ReferenceError: numberOfPosts is not defined (ao tentar acessar essa variável fora da função, obtemos um erro, pois ela só "existe" dentro da função em que foi declarada)
Além dessas duas maneiras de declarar uma var
, é possível atribuir outro valor à mesma variável. Desta forma:
var posts = 1;
var posts = 2;
console.log(posts); //2
E o hoisting, hein? 🏗️
Eu até falei que é possível atribuir outro valor a uma variável var
, mas tem algo um tanto complicado sobre fazer isso: o hoisting. Derivado do termo hoist em inglês, que significa "levantar" ou "içar" algo, o hoisting faz com que uma var
seja posicionada no início do contexto de execução no qual ela foi declarada – ou seja, esse mecanismo faz com que as variáveis var
que você declarou "subam" para o início do seu trecho de código antes mesmo que ele seja executado, algo que faz com que a sua variável, que antes tinha um valor, seja interpretada como undefined
, mais ou menos assim:
var texto = "dá pra evitar hoisting? D:";
//Variável var global
function writeOnScreen() {
console.log(texto);
var texto = "às vezes é inevitável...";
console.log(texto);
}
writeOnScreen();
//undefined
//às vezes é inevitável...
Mas ué, cadé o primeiro console.log?
Então, esse é o conceito do hoisting. Ao invés de interpretar a variável global e exibi-la em tela, esse mecanismo irá inicializar a variável global lá no início do bloco de função, e só depois é que ela será executada. Pra entender de vez como isso funciona, vamos pensar de acordo com o próprio JavaScript, passo a passo. É assim que esse bloco de função foi executado:
var texto = "dá pra evitar hoisting? D:";
//Variável var global
function writeOnScreen() {
var texto; //A variável global foi "levantada" durante a execução até o início deste bloco de função
console.log(texto); //undefined (pois ela só foi declarada aqui dentro, mas não foi definida)
var texto = "às vezes é inevitável..."; //Valor atribuído pela primeira vez (de acordo com o hoisting) dentro deste bloco de função
console.log(texto);
}
writeOnScreen();
//undefined
//às vezes é inevitável...
Aqui notamos uma das desvantagens de utilizar declarações var
. Caso ela sofra hoisting, será inicializada sempre com um valor undefined
. E claro, talvez a maior brecha de segurança da utilização do var
seja a facilidade em redefinir valores para uma declaração var
, independente do seu escopo de origem, prática que pode vir a causar inúmeros bugs na sua aplicação. Portanto – e essa é uma opinião minha, baseada no que estudei até aqui e ouvi de pessoas desenvolvedoras mais experientes -, com a chegada do ECMAScript 6, é possível evitar a utilização do var
, a não ser que a aplicação em questão seja utilizada em navegadores mais antigos, que não possuam suporte a let
e const
.
A chegada do let
O ECMAScript 6 trouxe diversas novidades, e uma delas foi a chegada da declaração let
, uma versão mais consistente de declaração de variáveis e que evita problemas de declaração repetida no mesmo escopo, por exemplo. A seguir, vamos ver algumas das funcionalidades do let
e como elas podem ser vantajosas para o nosso código:
- O
let
é declarado apenas em escopos de bloco, ou seja, qualquer pedaço do código delimitado por chaves ({}
) e a variável em questão estará disponível apenas neste escopo, dessa forma:
let age = "25";
if (age > 20) {
let name = "fulano";
console.log(name); //fulano
}
console.log(name); //name is not defined
- O
let
também não permite uma declaração repetida de uma variável como é visto novar
. É possível atribuir outro valor a uma variávellet
, mas não é permitido declará-la novamente. Por exemplo:
//Atribuição de um novo valor
let bolo = "morango";
bolo = "abacaxi";
console.log(bolo); //abacaxi
//Declaração repetida da variável
let bolo = "morango";
let bolo = "abacaxi"; //Identificador 'bolo' já foi declarado
Porém, isso é uma regra apenas para declarações de variáveis no mesmo escopo. Em escopos diferentes, essa declaração repetida funcionará normalmente, já que o JavaScript interpreta variáveis de escopos diferentes como declarações diferentes.
Acredito que o let
seja um tanto mais seguro que o var
nesse sentido. Ao declarar duas variáveis com o mesmo nome, mas em escopos diferentes, por exemplo, não temos o risco de estarmos mexendo na mesma variável, como ocorre em variáveis do tipo var
.
Por fim, a variável constante!
É assim que eu gosto de chamar a declaração const
, pra ser sincera. E, de fato, é mais ou menos isso. O const
armazena valores read-only que não podem ser alterados, ou seja, que se mantêm constantes. Algumas características do const
:
Variáveis declaradas como
const
, assim comolet
, só podem ser acessadas em escopo de bloco;Meio óbvio, mas é bom reforçar: variáveis
const
não podem ser redefinidas. Ou seja, você não poderá fazer isso:
const suco = "laranja";
suco = "limão"; //TypeError: Atribuição à variável constante.
//E nem isso:
const torta = "limão";
const torta = "banofee"; //Identificador 'torta' já foi declarado
- Justamente por ser uma variável constante ( 🤪 ), o
const
precisa ser inicializado com um valor atribuído. Caso contrário, o seguinte erro será mostrado:
const fruta;
//Missing initializer in const declaration
Certo, mas então qual delas eu devo usar?
Isso vai depender muito de qual aplicação você está desenvolvendo, e para qual browser. Se o seu projeto for direcionado a browsers mais antigos, continue utilizando var
sem problemas, pois não é garantido que browsers mais antigos forneçam suporte ao ECMAScript 6. Do contrário, se estamos falando de variáveis que vão ser alteradas, acredito no let
como a melhor forma de declarar variáveis mutáveis, ou pelo menos a mais segura e descomplicada. Já para variáveis read-only, o const
é a declaração que fornece maior segurança. :)
Isso é um pouquinho do que sei sobre declaração de variáveis no JavaScript como iniciante no assunto 😉 Caso tenham gostado ou queiram me enviar sugestões, dúvidas ou críticas, fiquem à vontade para comentar esse post ou me chamar lá no twitter @anestudies ;) Até breve!
Referências
https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Grammar_and_types
https://developer.mozilla.org/pt-BR/docs/Glossary/Scope
https://www.alura.com.br/artigos/entenda-diferenca-entre-var-let-e-const-no-javascript
https://walde.co/2016/02/15/javascript-hoisting-o-que-e/
Top comments (0)