📜 ⬆️ ⬇️

JavaScript Guide, Part 6: Exceptions, Semicolon, Pattern Literals

The themes of today's translation of the JavaScript tutorial will be exception handling, automatic semicolon features, and pattern literals.

Part 1: first program, language features, standards
Part 2: code style and program structure
Part 3: Variables, Data Types, Expressions, Objects
Part 4: Functions
Part 5: Arrays and Loops
Part 6: Exceptions, Semicolon, Pattern Literals
Part 7: strict mode, this keyword, events, modules, mathematical calculations
Part 8: ES6 feature overview
Part 9: Overview of ES7, ES8, and ES9 Capabilities



Exception Handling


When a problem occurs during code execution, it is expressed as an exception in JavaScript. If you do not take measures to handle exceptions, then, if they occur, the program execution stops, and an error message is displayed in the console.
')
Consider the following code snippet.

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') 

Here we have a function that we plan to use to process objects that have a value property. It returns this property. If you use this function according to its intended purpose, that is, you will not be given an object to work with which it is designed, when it is executed, no errors will be issued. But if you pass something inappropriate to it, in our case, a declared but uninitialized variable, then when you try to access the value property of the value undefined an error will occur. The error message will get to the console, the program will stop running.

This is how it looks when running this code in the Node.js environment.


TypeError exception in Node.js

If something similar is found in the JS code of a web page, a similar message will be sent to the browser console. If this happens in a real program, say - in the code of the web server, this behavior is highly undesirable. It would be good to have a mechanism that allows, without stopping the program, to catch the error, and then take steps to correct it. Such a mechanism exists in JavaScript; it is represented by the try...catch construction.

TryDesign try ... catch


The try...catch construct allows you to catch and handle exceptions. Namely, it includes a try block, which includes code that can cause an error, and a catch , to which control is passed when an error occurs. try blocks do not include absolutely all program code. There are those sections that can cause run-time errors. For example - calls to functions that have to work with some data obtained from external sources. If the structure of such data differs from that expected by the function, an error may occur. This is what the try...catch diagram looks like.

 try { // ,     } catch (e) { //  } 

If the code is executed without errors, the catch (exception handler) is not executed. If an error occurs, the object of the error is transmitted there and some actions are taken to combat this error.

Let us apply this construction in our example, protecting with it the dangerous sections of the program - those in which the function fn() called.

 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 

Let's look at the results of executing this code in the Node.js environment.


Error handling in Node.js

As you can see, if you compare this example with the previous one, now all the code is executed, and the one that is located before the problem line, and the one that is located after it. We “handle” the error by simply outputting to the console the values ​​of the message property of an object of type Error . What will be the handling of errors that have arisen in the actual code used, depends on the error.

Above, we discussed the try...catch , but, in fact, this construct includes another finally block.

Finally finally block


The finally block contains code that is executed regardless of whether or not an error has occurred in the code running in the try block. Here's what it looks like.

 try { //  } catch (e) { //  } finally { //  } 

The finally block can also be used if there is no catch block in the try...catch...finally block. With this approach, it is used in the same way as in the construction with the catch , for example, to release the resources occupied in the try block.

Try nested try blocks


Try blocks can be nested. An exception is processed in the nearest catch .

 try { //  try {   //   } finally {   // -  } } catch (e) { } 

In this case, if an exception occurs in an internal try block, it will be processed in an external catch .

▍ Self-generate exceptions


Exceptions can be generated independently using the throw statement. Here's what it looks like.

 throw value 

After this instruction is executed, control is transferred to the nearest catch , or if such a block cannot be found, the program is terminated. The exception value can be anything. For example, a user-defined error object.

About semicolons


Using semicolons in JavaScript code is optional. Some programmers do without them, relying on the automatic system of their arrangement, and putting them only where it is absolutely necessary. Some prefer to put them wherever possible. The author of this material refers to the category of programmers who seek to do without semicolons. He says that he decided to do without them in the fall of 2017, by setting up the Prettier so that it deletes them everywhere, where they can be dispensed with without their explicit insertion. In his opinion, the code without semicolons looks more natural and easier to read.

Perhaps we can say that the JS-developers community is divided into two camps with respect to a semicolon. At the same time, there are both JavaScript style guides, which prescribe explicit semicolon assignments, and guidelines that recommend doing without them.

All this is possible due to the fact that in JavaScript there is a system of automatic substitution of semicolons (Automatic Semicolon Insertion, ASI). However, the fact that in JS code, in many situations, you can do without these characters, and the fact that semicolons are automatically placed when preparing code for execution does not mean that the programmer does not need to know the rules by which this happens. Ignorance of these rules leads to errors.

▍ Rules for auto-substitution of semicolons


The JavaScript parser automatically adds semicolons when parsing program text in the following situations:

  1. When the next line starts with a code that interrupts the current code (the code of a certain command can be located on several lines).
  2. When the next line starts with a } , which closes the current block.
  3. When the end of the file with the program code is detected.
  4. In the line with the command return .
  5. In the line with the command break .
  6. In the line with the throw command.
  7. In the line with the command continue .

▍ Code examples that do not work as expected.


Here are some examples illustrating the above rules. For example, what do you think will be displayed as a result of executing the following code fragment?

 const hey = 'hey' const you = 'hey' const heyYou = hey + ' ' + you ['h', 'e', 'y'].forEach((letter) => console.log(letter)) 

When trying to execute this code, an Uncaught TypeError: Cannot read property 'forEach' of undefined error will be Uncaught TypeError: Cannot read property 'forEach' of undefined system, based on rule No. 1, tries to interpret the code as follows.

 const hey = 'hey'; const you = 'hey'; const heyYou = hey + ' ' + you['h', 'e', 'y'].forEach((letter) => console.log(letter)) 

The problem can be solved by putting a semicolon after the last but one line of the first example.

Here is another code snippet.

 (1 + 2).toString() 

The result of its execution will be the output line "3" . What happens if something like this appears in the following code snippet?

 const a = 1 const b = 2 const c = a + b (a + b).toString() 

In this situation, a TypeError: b is not a function error will appear TypeError: b is not a function since the above code will be interpreted as follows.

 const a = 1 const b = 2 const c = a + b(a + b).toString() 

Let us now look at an example based on rule No. 4.

 (() => { return {   color: 'white' } })() 

You might think that this IIFE will return an object containing the color property, but in fact it is not. Instead, the function will return the value undefined as the system adds a semicolon after the return command.

In order to solve a similar problem, the opening curly bracket of an object literal must be placed on the same line as the return command.

 (() => { return {   color: 'white' } })() 

If you look at the following code snippet, you might think that it will display 0 in the message box.

 1 + 1 -1 + 1 === 0 ? alert(0) : alert(2) 

But it prints 2, since, in accordance with rule No. 1, this code is represented as follows.

 1 + 1 -1 + 1 === 0 ? alert(0) : alert(2) 

Care should be taken when using semicolons in JavaScript. You can meet both hot supporters of semicolons and their opponents. In fact, deciding whether you need a semicolon in your code, you can rely on the fact that JS supports their automatic substitution, but everyone has to decide for himself whether they are needed in his code or not. The main thing is to consistently and reasonably apply the chosen approach. With regard to the semicolon arrangement and code structure, it is recommended to adhere to the following rules:


In general, we can say that, whether you put semicolons yourself, or rely on their automatic placement, test the code to make sure that it works exactly as expected.

Quotes and pattern literals


Let's talk about the use of quotes in JavaScript. Namely, we are talking about the following valid quote types in JS programs:


Single and double quotes, in general, can be considered the same.

 const test = 'test' const bike = "bike" 

There is practically no difference between them. Perhaps the only noticeable difference is that in the strings enclosed in single quotes, the single quotation symbol must be escaped, and in the strings enclosed in double quotation marks - the double one.

 const test = 'test' const test = 'te\'st' const test = 'te"st' const test = "te\"st" const test = "te'st" 

In various style guides, you can find a recommendation for using single quotes, as well as a recommendation for using double quotes. The author of this material says that in JS-code tends to use only single quotes, using double only in HTML-code.

Back quotes appeared in JavaScript with the release of the ES6 standard in 2015. They, besides other new features, allow conveniently describing multi-line strings. Such strings can also be specified using regular quotes - using the escape sequence \n . It looks like this.

 const multilineString = 'A string\non multiple lines' 

Back quotes (usually the button to enter them is to the left of the numeric key 1 on the keyboard) allow you to do without \n .

 const multilineString = `A string on multiple lines` 

But the possibilities of reverse quotes are not limited to this. So, if a string is described using backward quotes, it is possible to substitute values ​​in it using the ${} construct, which are the result of evaluating JS expressions.

 const multilineString = `A string on ${1+1} lines` 

Such strings are called template literals.

Pattern literals are distinguished by the following features:


Let's talk about these opportunities.

▍Multiline text


When asking, using back quotes, multi-line texts, you need to remember that spaces in such texts are just as important as other characters. For example, consider the following multi-line text.

 const string = `First               Second` 

His conclusion will give something like the following.

 First               Second 

That is, it turns out that when this text was entered in the editor, it is possible that the programmer expected that the words First and Second , when outputted, would be strictly under each other, but in fact this is not the case. In order to circumvent this problem, you can begin multiline text with a line feed, and, immediately after the closing back quote, call the trim() method, which will remove the whitespace at the beginning or end of the line. These characters, in particular, include spaces and tabs. The end of line characters will also be removed.

It looks like this.

 const string = ` First Second`.trim() 

▍ Interpolation


Interpolation here refers to the conversion of variables and expressions to strings. This is done using the ${} construct.

 const variable = 'test' const string = `something ${ variable }` //something test 

You can add anything to the ${} block, even expressions.

 const string = `something ${1 + 2 + 3}` const string2 = `something ${foo() ? 'x' : 'y' }` 

The text something 6 will fall into the string constant, or the text something x , or the text something y will be written to the constant string2 . It depends on whether the foo() function returns true or false (here we use the ternary operator, which, if what is before the question mark, is true, returns what comes after the question mark, otherwise returning what comes after the colon).

▍Tagged patterns


Tagged templates are used in many popular libraries. Among them - Styled Components , Apollo , GraphQL .

The fact that such patterns are output is subject to some kind of logic defined by the function. Here is a slightly revised example given in one of our publications , illustrating the work with tagged patterned strings.

 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. 

Here, if the number 8 written in the esth constant, the string ES 8 is awesome . Otherwise there will be another line. For example, if esth has the number 6 , then it will look like ES 6 is good .

Styled Components uses tagged templates to define CSS strings.

 const Button = styled.button` font-size: 1.5em; background-color: black; color: white; `; 

In Apollo, they are used to define GraphQL queries.

 const query = gql` query {   ... } ` 

Knowing how the tagged templates are arranged, it is easy to understand that styled.button and gql from the previous examples are just functions.

 function gql(literals, ...expressions) { } 

For example, the gql() function returns a string that can be the result of any calculation. The literals parameter of this function is an array containing the contents of the template literal expresions into parts, expresions contains the results of the evaluation of expressions.

Let's sort the next line.

 const string = helper`something ${1 + 2 + 3} ` 

The literals array containing two elements will get to the helper function. In the first there will be the text something with a space after it, in the second - the empty line - that is, what is between the expression ${1 + 2 + 3} and the end of the line. In the array espressions will be one element - 6 .
Here is a more complex example.

 const string = helper`something another ${'x'} new line ${1 + 2 + 3} test` 

Here, the following array will fall into the helper function, as the first parameter.

 [ 'something\nanother ', '\nnew line ', '\ntest' ] 

The second array will look like this.

 [ 'x', 6 ] 

Results


Today we talked about exception handling, about semicolon auto-substitution and about template literals in JavaScript. Next time we will look at some more important concepts of the language. In particular - work in strict mode, timers, mathematical calculations.

Dear readers! Do you use the capabilities of tagged templates in javascript?

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


All Articles