Os tópicos nesta parte da tradução do tutorial em JavaScript serão manipulação de exceções, recursos automáticos de ponto e vírgula e literais de modelo.
→
Parte 1: primeiro programa, recursos de linguagem, padrões→
Parte 2: estilo do código e estrutura do programa→
Parte 3: variáveis, tipos de dados, expressões, objetos→
Parte 4: recursos→
Parte 5: matrizes e loops→
Parte 6: exceções, ponto e vírgula, literais curinga→
Parte 7: modo estrito, esta palavra-chave, eventos, módulos, cálculos matemáticos→
Parte 8: Visão geral dos recursos do ES6→
Parte 9: Visão geral dos padrões ES7, ES8 e ES9
Manipulação de exceção
Quando um problema ocorre durante a execução do código, ele é expresso como uma exceção no JavaScript. Se você não tomar medidas para lidar com exceções, quando elas ocorrerem, o programa será interrompido e uma mensagem de erro será exibida no console.
Considere o seguinte snippet de código.
let obj = {value: 'message text'} let notObj let fn = (a) => a.value console.log(fn(obj))
Aqui temos uma função que planejamos usar para processar objetos que possuem a propriedade
value
. Ela retorna essa propriedade. Se você usar esta função para a finalidade pretendida, ou seja, para transferir para ela um objeto com o qual foi projetada para trabalhar, nenhum erro será gerado quando for executado. Mas se você passar algo inapropriado para ele, no nosso caso, uma variável declarada, mas não inicializada, ocorrerá um erro ao tentar acessar a propriedade
value
de valor
undefined
. Uma mensagem de erro será exibida no console, a execução do programa será interrompida.
Aqui está o que parece quando você executa esse código no Node.js.
Exceção TypeError no Node.jsSe algo assim ocorrer no código JS de uma página da web, uma mensagem semelhante será enviada ao console do navegador. Se isso acontece em um programa real, digamos - no código do servidor da Web, esse comportamento é extremamente indesejável. Seria bom ter um mecanismo que permita, sem interromper o programa, capturar o erro e tomar medidas para corrigi-lo. Esse mecanismo existe no JavaScript, é representado pelo construto
try...catch
.
Tryconstruction try ... catch
A construção
try...catch
permite capturar e manipular exceções. Nomeadamente, inclui um bloco
try
, que inclui código que pode causar um erro, e um
catch
, no qual o controle é transferido quando ocorre um erro.
try
blocos de
try
não incluem absolutamente todo o código do programa. As partes dele que podem causar erros de tempo de execução são colocadas lá. Por exemplo, chamadas para funções que precisam trabalhar com determinados dados recebidos de fontes externas. Se a estrutura desses dados for diferente do que a função espera, pode ocorrer um erro. Aqui está a aparência do diagrama de design
try...catch
.
try {
Se o código for executado sem erros, o
catch
(manipulador de exceções) não será executado. Se ocorrer um erro, o objeto de erro é transferido para lá e algumas ações são tomadas para combater esse erro.
Aplicamos essa construção em nosso exemplo, protegendo com sua ajuda seções perigosas do programa - aquelas nas quais a função
fn()
chamada.
let obj = {value: 'message text'} let notObj let fn = (a) => a.value try { console.log(fn(obj)) } catch (e) { console.log(e.message) } console.log('Before')
Vejamos os resultados da execução desse código no Node.js.
Tratamento de erros no Node.jsComo você pode ver, se você comparar este exemplo com o anterior, agora todo o código será executado, o que está localizado antes da linha do problema e o que está localizado depois dele. Nós “processamos” o erro simplesmente imprimindo no console os valores da propriedade
message
do objeto
Error . Qual será o tratamento do erro que ocorreu no código realmente usado depende do erro.
Discutimos o bloco
try...catch
acima, mas, de fato, esse construto inclui outro bloco -
finally
.
Block finalmente bloqueia
O bloco
finally
contém código que é executado independentemente de um erro ter ocorrido ou não no código que é executado no bloco
try
. Aqui está como fica.
try {
O bloco
finally
também pode ser usado se o bloco
try...catch...finally
não tiver um
catch
. Nesta abordagem, é usado da mesma maneira que na construção com o
catch
, por exemplo, para liberar recursos ocupados no bloco
try
.
▍ Blocos de tentativa aninhados
Os blocos de tentativa podem ser aninhados juntos. Nesse caso, a exceção é processada no
catch
mais próximo.
try {
Nesse caso, se ocorrer uma exceção no bloco
try
interno, ela será processada no
catch
externo.
Exception Exceção auto-gerada
Exceções podem ser lançadas por você, usando a instrução
throw
. Aqui está como fica.
throw value
Após a execução desta instrução, o controle é transferido para o
catch
mais próximo ou, se esse bloco não for encontrado, o programa será interrompido. O valor da exceção pode ser qualquer coisa. Por exemplo, um objeto de erro definido pelo usuário.
Sobre ponto e vírgula
O uso de ponto e vírgula no JavaScript é opcional. Alguns programadores ficam sem eles, contando com um sistema de arranjo automático para eles e colocando-os somente onde for absolutamente necessário. Algumas pessoas preferem colocá-los sempre que possível. O autor deste material refere-se à categoria de programadores que desejam passar sem ponto e vírgula. Ele diz que decidiu ficar sem eles no outono de 2017, definindo Prettier para excluí-los sempre que possível sem a inserção explícita deles. Na sua opinião, código sem ponto e vírgula parece mais natural e fácil de ler.
Talvez possamos dizer que a comunidade de desenvolvedores de JS é dividida, em relação ao ponto e vírgula, em dois campos. Ao mesmo tempo, também existem guias de estilo JavaScript que prescrevem ponto-e-vírgula explícito e guias que recomendam ficar sem eles.
Tudo isso é possível devido ao fato de o JavaScript possuir um sistema para ponto e vírgula automática (Inserção automática de ponto e vírgula, ASI). No entanto, o fato de que no código JS, em muitas situações, você pode ficar sem esses caracteres, e o fato de os pontos-e-vírgulas serem colocados automaticamente ao preparar o código para execução, não significa que o programador não precise conhecer as regras pelas quais isso acontece. A ignorância dessas regras leva a erros.
▍ Regras para ponto e vírgula automático
O analisador JavaScript adiciona automaticamente ponto-e-vírgula ao analisar o texto do programa nas seguintes situações:
- Quando a próxima linha começa com um código que interrompe o código atual (o código de um determinado comando pode estar localizado em várias linhas).
- Quando a próxima linha começa com o caractere
}
, que fecha o bloco atual. - Quando o final do arquivo com o código do programa for detectado.
- Na linha com o comando de
return
. - Na linha com o comando
break
. - Na linha com o comando
throw
. - Na linha com o comando
continue
.
▍ Exemplos de código que não funcionam conforme o esperado
Aqui estão alguns exemplos que ilustram as regras acima. Por exemplo, o que você acha que será exibido como resultado da execução do seguinte fragmento de código?
const hey = 'hey' const you = 'hey' const heyYou = hey + ' ' + you ['h', 'e', 'y'].forEach((letter) => console.log(letter))
Quando você tenta executar esse código, será
Uncaught TypeError: Cannot read property 'forEach' of undefined
um erro
Uncaught TypeError: Cannot read property 'forEach' of undefined
sistema
Uncaught TypeError: Cannot read property 'forEach' of undefined
, com base na regra nº 1, ele tenta interpretar o código da seguinte maneira.
const hey = 'hey'; const you = 'hey'; const heyYou = hey + ' ' + you['h', 'e', 'y'].forEach((letter) => console.log(letter))
O problema pode ser resolvido colocando um ponto e vírgula após a penúltima linha do primeiro exemplo.
Aqui está outro pedaço de código.
(1 + 2).toString()
O resultado de sua execução será a saída da string
"3"
. Mas o que acontece se algo assim aparecer no próximo snippet de código?
const a = 1 const b = 2 const c = a + b (a + b).toString()
Nessa situação, um erro
TypeError: b is not a function
será exibido
TypeError: b is not a function
pois o código acima será interpretado da seguinte maneira.
const a = 1 const b = 2 const c = a + b(a + b).toString()
Vamos agora dar uma olhada em um exemplo baseado na regra 4.
(() => { return { color: 'white' } })()
Você pode pensar que esse IIFE retornará um objeto que contém a propriedade
color
, mas na verdade não é. Em vez disso, a função retornará
undefined
porque o sistema adiciona um ponto-e-vírgula após o comando de
return
.
Para resolver um problema semelhante, a chave de abertura do literal do objeto deve ser colocada na mesma linha do comando de
return
.
(() => { return { color: 'white' } })()
Se você observar o seguinte fragmento de código, poderá pensar que ele exibirá
0
na caixa de mensagem.
1 + 1 -1 + 1 === 0 ? alert(0) : alert(2)
Mas gera 2, porque, de acordo com a regra nº 1, esse código é representado da seguinte maneira.
1 + 1 -1 + 1 === 0 ? alert(0) : alert(2)
Você deve ter cuidado ao usar ponto e vírgula no JavaScript. Você pode conhecer ambos os fervorosos apoiadores de ponto e vírgula e seus oponentes. De fato, ao decidir se o ponto-e-vírgula é necessário no seu código, você pode confiar no fato de o JS oferecer suporte à substituição automática, mas todos devem decidir por si próprios se são necessários no código ou não. O principal é aplicar a abordagem escolhida de forma consistente e razoável. Em relação à colocação de ponto e vírgula e à estrutura do código, podemos recomendar as seguintes regras:
- Usando o comando
return
, organize o que deve retornar da função na mesma linha que o comando. O mesmo vale para os comandos break
, throw
, continue
. - Preste atenção especial às situações em que uma nova linha de código começa com um colchete, pois essa linha pode ser combinada automaticamente com a anterior e apresentada pelo sistema como uma tentativa de chamar uma função ou uma tentativa de acessar um elemento da matriz.
Em geral, pode-se dizer que, independentemente de você colocar ponto-e-vírgula ou confiar no posicionamento automático, teste o código para garantir que ele funcione exatamente como o esperado.
Aspas e literais curinga
Vamos falar sobre os recursos do uso de aspas em JavaScript. Ou seja, estamos falando dos seguintes tipos de cotação permitidos nos programas JS:
- Aspas simples.
- Aspas duplas.
- Citações de volta.
As aspas simples e duplas, em geral, podem ser consideradas iguais.
const test = 'test' const bike = "bike"
Praticamente não há diferença entre eles. Talvez a única diferença notável seja que, nas cadeias de caracteres entre aspas simples, você precisa escapar do caractere de aspas simples e nas cadeias de caracteres entre aspas duplas, o caractere é duplo.
const test = 'test' const test = 'te\'st' const test = 'te"st' const test = "te\"st" const test = "te'st"
Em guias de estilo diferentes, você encontra uma recomendação para usar aspas simples e uma recomendação para usar aspas duplas. O autor deste material diz que, no código JS, ele se esforça para usar aspas únicas, usando aspas duplas apenas no código HTML.
Os backticks apareceram em JavaScript com o lançamento do padrão ES6 em 2015. Eles, entre outros novos recursos, possibilitam descrever convenientemente seqüências de várias linhas. Essas cadeias também podem ser especificadas usando aspas regulares - usando a sequência de escape
\n
. Parece assim.
const multilineString = 'A string\non multiple lines'
Vírgulas invertidas (normalmente o botão para inseri-las está localizado à esquerda da tecla numérica 1 no teclado) ficam sem
\n
.
const multilineString = `A string on multiple lines`
Mas as possibilidades de aspas não estão limitadas a isso. Portanto, se uma string é descrita usando aspas, é possível substituir valores do cálculo de expressões JS nela usando a construção
${}
.
const multilineString = `A string on ${1+1} lines`
Tais cadeias são chamadas literais de modelo.
Literais de modelo têm os seguintes recursos:
- Eles suportam texto de várias linhas.
- Eles possibilitam a interpolação de strings; expressões internas podem ser usadas neles.
- Eles permitem que você trabalhe com modelos marcados, possibilitando a criação de seus próprios idiomas específicos do domínio (DSL, idioma específico do domínio).
Vamos falar sobre esses recursos.
UltTexto multilíngue
Ao definir textos com várias linhas com aspas, é necessário lembrar que os espaços nesses textos são tão importantes quanto os outros caracteres. Por exemplo, considere o seguinte texto multilinha.
const string = `First Second`
Sua conclusão dará aproximadamente o seguinte.
First Second
Ou seja, quando esse texto foi inserido no editor, é possível que o programador esperasse que as palavras
First
e
Second
, ao serem exibidas, aparecessem estritamente uma na outra, mas, na verdade, não é assim. Para contornar esse problema, você pode iniciar o texto de múltiplas linhas com um avanço de linha e, imediatamente após fechar as aspas, chamar o método
trim()
, que removerá os caracteres de espaço em branco no início ou no final da linha. Esses caracteres, em particular, incluem espaços e tabulações. Os caracteres de fim de linha também serão excluídos.
Parece assim.
const string = ` First Second`.trim()
▍ Interpolação
Por interpolação, aqui queremos dizer a conversão de variáveis e expressões em strings. Isso é feito usando a construção
${}
.
const variable = 'test' const string = `something ${ variable }`
Você pode adicionar qualquer coisa ao bloco
${}
- mesmo expressões.
const string = `something ${1 + 2 + 3}` const string2 = `something ${foo() ? 'x' : 'y' }`
O texto
something 6
entrará na constante da
string
, ou o texto
something x
ou o texto
something y
será gravado na constante
string2
. Depende se a função
foo()
retorna true ou false (o operador ternário é usado aqui, que, se o que for antes do ponto de interrogação for verdadeiro, retorna o que vem depois do ponto de interrogação, retornando o que vem após o cólon).
TemplatesModelos marcados
Modelos marcados são usados em muitas bibliotecas populares. Entre eles estão
Styled Components ,
Apollo ,
GraphQL .
A saída de tais padrões está sujeita a alguma lógica definida pela função. Aqui está um exemplo ligeiramente revisado em uma de nossas
publicações, ilustrando como trabalhar com seqüências de caracteres de modelo marcadas.
const esth = 8 function helper(strs, ...keys) { const str1 = strs[0]
Aqui, se o número
8
escrito na constante
esth
, a linha
ES 8 is awesome
será em
es
. Caso contrário, haverá outra linha. Por exemplo, se
esth
número
6
, parecerá que
ES 6 is good
.
O Styled Components usa modelos marcados para definir seqüências de caracteres CSS.
const Button = styled.button` font-size: 1.5em; background-color: black; color: white; `;
No Apollo, eles são usados para definir consultas GraphQL.
const query = gql` query { ... } `
Sabendo como os modelos com tags funcionam, é fácil entender que
styled.button
e
gql
dos exemplos anteriores são apenas funções.
function gql(literals, ...expressions) { }
Por exemplo, a função
gql()
retorna uma string que pode ser o resultado de qualquer cálculo. O parâmetro
literals
dessa função é uma matriz que contém o conteúdo de um literal de modelo dividido em partes,
expresions
contém os resultados da avaliação de expressões.
Vamos analisar a próxima linha.
const string = helper`something ${1 + 2 + 3} `
A função
helper
obtém a matriz de
literals
contém dois elementos. No primeiro, haverá
something
com um espaço a seguir, no segundo haverá uma linha vazia - ou seja, o que está entre a expressão
${1 + 2 + 3}
e o final da linha. Haverá um elemento na matriz de
espressions
-
6
.
Aqui está um exemplo mais complexo.
const string = helper`something another ${'x'} new line ${1 + 2 + 3} test`
Aqui, na função
helper
, a próxima matriz será o primeiro parâmetro.
[ 'something\nanother ', '\nnew line ', '\ntest' ]
A segunda matriz será assim.
[ 'x', 6 ]
Sumário
Hoje falamos sobre manipulação de exceções, sobre substituição automática de ponto e vírgula e sobre literais de modelo em JavaScript. Da próxima vez, examinaremos alguns conceitos mais importantes da linguagem. Em particular - trabalhe em modo estrito, temporizadores, cálculos matemáticos.
Caros leitores! Você usa os recursos de modelos marcados em JavaScript?
