Guia do JavaScript Parte 6: Exceções, ponto e vírgula, literais de modelo

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)) //message text console.log('Before') //Before console.log(fn(notObj)) //,    console.log('After') 

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.js

Se 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 { // ,     } catch (e) { //  } 

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') //Before try {   console.log(fn(notObj)) } catch (e) {   console.log(e.message) //Cannot read property 'value' of undefined } console.log('After') //After 

Vejamos os resultados da execução desse código no Node.js.


Tratamento de erros no Node.js

Como 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 { //  } catch (e) { //  } finally { //  } 

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 { //  try {   //   } finally {   // -  } } catch (e) { } 

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:

  1. 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).
  2. Quando a próxima linha começa com o caractere } , que fecha o bloco atual.
  3. Quando o final do arquivo com o código do programa for detectado.
  4. Na linha com o comando de return .
  5. Na linha com o comando break .
  6. Na linha com o comando throw .
  7. 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 }` //something test 

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] //ES const str2 = strs[1] //is let additionalPart = '' if (keys[0] == 8) { //8   additionalPart = 'awesome' } else {   additionalPart = 'good' } return `${str1}${keys[0]}${str2}${additionalPart}.` } const es = helper`ES ${esth} is ` console.log(es) //ES 8 is awesome. 

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?

Source: https://habr.com/ru/post/pt430376/


All Articles