Return in javascript how it works. Expressive JavaScript: Functions. Local and global variables

💖 Do you like it? Share the link with your friends

Jump Statements and Exception Handling

Another category of JavaScript operators are jump operators. As the name suggests, these operators cause the JavaScript interpreter to jump to another location in the program code. The break statement causes the interpreter to jump to the end of a loop or other statement. The continue statement causes the interpreter to skip the rest of the loop body, jump back to the beginning of the loop, and begin executing a new iteration. JavaScript has the ability to label statements with names, so break and continue statements can explicitly indicate which loop or other statement they belong to.

The return statement causes the interpreter to jump from the called function back to the point at which it was called and return the value of the call. The throw statement throws an exception and is intended to work in conjunction with try/catch/finally statements that define a block program code to handle the exception. This is a rather complex type of jump operator: when an exception occurs, the interpreter jumps to the nearest enclosing exception handler, which may be in the same function or higher in the return stack of the called function.

All of these jump operators are described in more detail in the following subsections.

Instruction marks

Any instruction can be marked with an identifier and a colon:

ID: instruction

By marking an instruction, you give it a name, which can then be used as a reference anywhere in the program. You can mark any instruction, but it only makes sense to mark instructions that have a body, such as loops and conditional statements.

By assigning a name to a loop, it can then be used in break and continue statements, inside a loop to exit from it, or to jump to the beginning of the loop to the next iteration. The break and continue statements are the only JavaScript statements that can include labels—we'll cover them in more detail later. The following is an example of a while statement with a label and a continue statement using that label:

Mainloop: while (token != null) ( // Program code omitted... continue mainloop; // Move to the next iteration of the named loop)

The identifier used as a statement label can be any valid JavaScript identifier except a reserved word. Label names are separated from variable and function names, so identifiers that match variable or function names can be used as labels.

Instruction labels are defined only within the instructions to which they apply (and, of course, within the instructions nested within them). Nested statements cannot be tagged with the same identifiers as their containing statements, but two independent statements can be tagged with the same label. Flagged instructions can be flagged again. That is, any instruction can have many labels.

break statement

The break statement causes the innermost loop or switch statement to immediately exit. We have previously seen examples of using the break statement inside a switch statement. In loops, it is typically used to immediately exit the loop when the loop needs to terminate for some reason.

When a loop has very complex termination conditions, it is often easier to implement those conditions using a break statement than to try to express them in a single loop conditional expression. The following example tries to find an array element with a specific value. The loop ends normally when it reaches the end of the array, or with a break statement once the value being sought is found:

Var arr = ["a","b","c","d","d"], result; for (var i = 0; i

In JavaScript, you can specify the name of the label after the break keyword (identifier without a colon):

break label_name;

When a break statement is used with a label, it jumps to the end of the named statement or terminates its execution. If there is no statement with the specified label, attempting to use this form of the break statement generates a syntax error. The named statement does not have to be a loop or switch statement. A break statement with a label can break out of any containing statement. A wrapper instruction may even be a simple block of instructions enclosed in curly braces for the sole purpose of labeling it.

You cannot insert a newline character between the break keyword and the label name. This is because the JavaScript interpreter automatically inserts missing semicolons: if you split a line of code between the break keyword and the following label, the interpreter will assume that you meant the simple form of the statement without the label, and will add a semicolon.

A labeled break statement is needed only when you want to interrupt the execution of a statement that is not the closest enclosing loop or switch statement.

Continue operator

The continue statement is similar to the break statement. However, instead of exiting the loop, the continue statement starts a new iteration of the loop. The syntax of the continue statement is as simple as the syntax of the break statement. The continue statement can also be used with a label.

The continue statement, both in the form without a label and with a label, can only be used in the body of a loop. Using it anywhere else results in a syntax error. When the continue statement is executed, the current iteration of the loop is interrupted and the next one begins. For different types cycles this means different things:

    In a while loop, the expression specified at the beginning of the loop is checked again, and if it is true, the body of the loop is executed from the beginning.

    A do/while loop jumps to the end of the loop, where the condition is checked again before executing the loop again.

    The for loop evaluates the increment expression and evaluates the test expression again to determine whether the next iteration should be performed.

    In a for/in loop, the loop starts over by assigning the specified variable to the name of the next property.

Note the differences in the behavior of the continue statement in while and for loops. The while loop returns directly to its condition, and for loop first evaluates the increment expression and then returns to the condition. The following example shows the use of a continue statement without a label to exit the current loop iteration for even numbers:

Var sum = 0; // Calculate the sum of odd numbers from 0 - 10 for (var i = 0; i

The continue statement, like break, can be used in nested loops in a form that includes a label, and then the loop that is restarted will not necessarily be a loop that directly contains the continue statement. Additionally, as with break, line breaks are not allowed between the continue keyword and the label name.

return statement

A function call is an expression and, like all expressions, has a value. The return statement inside functions is used to determine the value returned by the function. The return statement can only appear in the body of a function. Its presence in any other place is a syntax error. When a return statement is executed, the function returns the value of the expression to the calling program. For example:

If a function does not have a return statement, when it is called, the interpreter will execute the statements in the function body one by one until it reaches the end of the function, and then return control to the program that called it. In this case, the calling expression will return undefined. The return statement is often last instruction in the function, but this is completely optional: the function will return control to the calling program as soon as a return statement is reached, even if it is followed by other statements in the function body.

The return statement can also be used without an expression, in which case it simply aborts the function and returns undefined to the calling program. For example:

Function myFun(arr) ( // If the array contains negative numbers, abort the function for (var i = 0; i

throw statement

An exception is a signal indicating that some kind of exceptional situation or error has occurred. Throwing an exception is a way to signal such an error or exception. To catch an exception means to process it, i.e. take actions necessary or appropriate to recover from the exception.

IN JavaScript exceptions raised when a run-time error occurs and when the program explicitly raises it using a throw statement. Exceptions are caught using try/catch/finally statements, which are described later.

The throw statement has the following syntax:

throw expression;

The result of the expression can be a value of any type. The throw statement can be passed a number representing an error code or a string containing the text of the error message. The JavaScript interpreter throws exceptions using an instance of the Error class of one of its subclasses, and you can use a similar approach. The Error object has a property name, which defines the type of error, and the property message, containing the string passed to the constructor function. The following is an example of a function that raises an Error object when called with an invalid argument:

// Number factorial function function factorial(number) ( // If the input argument is not a valid value, // an exception is thrown! if (number 1; i *= number, number--); /* empty loop body */ return i ; ) console.log("5! = ", factorial(5)); console.log("-3! = ", factorial(-3));

When an exception is raised, the JavaScript interpreter immediately interrupts normal program execution and jumps to the nearest exception handler. Exception handlers use the try/catch/finally catch clause, which is described in the next section.

If the code block in which the exception occurred does not have a corresponding catch construct, the interpreter examines the next outer code block and checks whether an exception handler is associated with it. This continues until a handler is found.

If an exception is thrown in a function that does not contain a try/catch/finally construct to handle it, the exception propagates up to the code that called the function. This way exceptions are propagated through the lexical structure JavaScript methods up the call stack. If an exception handler is never found, the exception is treated as an error and reported to the user.

try/catch/finally construct

The try/catch/finally construct implements the exception handling mechanism in JavaScript. The try statement in this construct simply defines a block of code in which exceptions are handled. The try block is followed by a catch statement with a block of statements that are called if an exception occurs anywhere in the try block. The catch statement is followed by a finally block, which contains the final code that is guaranteed to run regardless of what happens in the try block.

Both the catch block and the finally block are optional, but at least one of them must be present after the try block. Try, catch and finally blocks start and end curly braces. This is a required part of the syntax and cannot be omitted, even if there is only one instruction in between.

The following snippet illustrates the syntax and purpose of the try/catch/finally construct:

Try ( // This code usually runs smoothly from start to finish. // But at some point it may throw an exception // either directly using the throw statement, or indirectly // by calling a method that throws the exception. ) catch (ex) ( // The statements in this block are executed if and only if an exception // occurs in the try block. These statements can use the local variable ex, which // refers to an Error object or another value specified in the throw statement. // This block can either handle the exception in some way, // ignore it while doing something else, or re-throw the exception // using a throw statement. ) finally ( // This block contains statements that are always executed, regardless of , // what happened in the try block They are executed if the try block has completed: // 1) as usual, having reached the end of the block // 2) due to a break, continue or return statement // 3) with the exception handled by the one in catch block above // ​​4) with an uncaught exception that continues to propagate // to higher levels)

Note that the catch keyword is followed by an identifier in parentheses. This identifier is similar to a function parameter. When an exception is caught, this parameter will be assigned to the exception (for example, an Error object). Unlike a regular variable, the identifier associated with a catch statement exists only in the body of the catch block.

The following is a more realistic example of a try/catch construct. It calls the factorial() method defined in the previous example and the client JavaScript prompt() and alert() methods to organize input and output:

Try ( // Request a number from the user var n = Number(prompt("Enter positive number", "")); // Calculate the factorial of a number, assuming // that the input data is correct var f = factorial(n); // Print the result alert(n + "! = " + f); ) catch (ex) ( // If the data is incorrect, control will be transferred here alert(ex); // Notify the user about the error )

If the user enters a negative number, a warning message appears:

This is an example of a try/catch construct without a finally clause. Although finally is not used as often as catch, it is still useful sometimes. The finally block is guaranteed to execute if at least some part of the try block has been executed, regardless of how the code in the try block completed execution. This feature is typically used to perform final operations after executing code in a try continuation.

In a normal situation, control reaches the end of the try block and then moves to the finally block, which performs the necessary final operations. If control exits a try block as a result of a return, continue, or break statement, the finally block is executed before control is transferred elsewhere.

If an exception occurs in a try block and there is a corresponding catch block to handle it, control first passes to the catch block and then to the finally block. If there is no local catch block, control first passes to the finally block and then moves to the nearest outer catch block that can handle the exception.

If the finally block itself transfers control using a return, continue, break, or throw statement or by calling a method that throws an exception, the pending transfer command is canceled and a new one is executed. For example, if a finally block throws an exception, that exception will replace any previously thrown exception.

Functions are one of the most important building blocks of code in JavaScript.

Functions consist of a set of commands and usually perform one specific task (for example, summing numbers, calculating roots, etc.).

Code placed in a function will only be executed after an explicit call to this function.

Function Declaration

1. Syntax:

//Declaration of the function functionFunctionname(ln1, ln2)( Function code) //Calling the functionFunctionname(ln1,lr2);

2. Syntax:

//Declaration of the function var function name=function(ln1, ln2)(Function code) //Calling the function function name(ln1,lr2);

functionname specifies the name of the function. Each function on the page must have a unique name. The function name must be specified in Latin letters and must not begin with numbers.

ln1 and ln2 are variables or values ​​that can be passed into the function. An unlimited number of variables can be passed to each function.

Please note: even if no variables are passed to the function, do not forget to insert parentheses "()" after the function name.

Please note that function names in JavaScript are case sensitive.

Example JavaScript function

The messageWrite() function in the example below will only be executed after the button is clicked.

Note that this example uses the onclick event. JavaScript Events will be discussed in detail later in this textbook.

// The function writes text to the page function messageWrite() ( document.write("This text was written to the page using JavaScript!"); )

Passing Variables to Functions

You can pass an unlimited number of variables to functions.

Please note: all manipulations with variables inside functions are actually performed not on the variables themselves, but on their copy, so the contents of the variables themselves do not change as a result of executing functions.

/* Let's define a function that adds 10 to the passed variable and displays the result on the page */ function plus(a)( a=a+10; document.write("Function output: " + a+"
"); ) var a=25; document.write("The value of the variable before the function call: "+a+"
"); // Call the function by passing it the variable a plus(a); document.write("Value of the variable after calling the function: "+a+"
");

Quick view

To access a global variable from a function rather than a copy of it, use window.variable_name.

Function plus(a)( window.a=a+10; ) var a=25; document.write("The value of the variable before the function call: "+a+"
"); plus(a); document.write("Value of the variable after calling the function: "+a+"
");

Quick view

return command

With the return command you can return values ​​from functions.

//The sum function returns the sum of the variables passed to it function sum(v1,v2)( return v1+v2; ) document.write("5+6=" + sum(5,6) + "
"); document.write("10+4=" + sum(10,4) + "
");

Quick view

Built-in functions

In addition to user-defined functions, JavaScript also has built-in functions.

For example, the built-in isFinite function allows you to check whether the passed value is a valid number.

Document.write(isFinite(40)+"
"); document.write(isFinite(-590)+"
"); document.write(isFinite(90.33)+"
"); document.write(isFinite(NaN)+"
"); document.write(isFinite("This is a string")+"
");

Quick view

Note: full list You can find built-in JavaScript functions in our .

Local and global variables

Variables created inside functions are called local variables. You can access such variables only within the functions in which they were defined.

After the function code completes execution, such variables are destroyed. This means that variables with the same name can be defined in different functions.

Variables that are created outside of function code are called global variables; such variables can be accessed from anywhere in the code.

If you declare a variable without var inside a function, it also becomes global.

Global variables are destroyed only after the page is closed.

//Declare global variables var1 and var2 var var1="var1 exists"; var var2; function func1() ( //Assign var2 a value inside the function func1 var var2="var2 exists"; ) //From another function, print the contents of the variable var1 and var2 to the page function func2() ( //Print the contents of the variable var1 document.write( var1 + "
"); //Output the contents of the variable var2 document.write(var2); )

Quick view

Note that when printed to the screen, var2 will have an empty value because func1 operates on the local "version" of var2.

Using Anonymous Functions

Functions that do not contain a name when declared are called anonymous.

Anonymous functions are basically declared not to be subsequently called from code like regular functions, but to be passed to other functions as a parameter.

Function arrMap(arr,func)( var res=new Array; for (var i=0;i target) return null; else return find(start + 5, "(" + history + " + 5)") || find (start * 3, "(" + history + " * 3)"); ) return find(1, "1"); ) console.log(findSolution(24)); // → (((1 * 3) + 5) * 3)

This example does not necessarily find the shortest solution - it is satisfied by any. I don't expect you to immediately understand how the program works. But let's understand this great exercise in recursive thinking.

The inner function find does recursion. It takes two arguments - the current number and a string that contains a record of how we arrived at this number. And it returns either a string showing our sequence of steps, or null.

To do this, the function performs one of three actions. If the given number is equal to the goal, then the current story is precisely the way to achieve it, so it returns. If the given number is larger than the goal, there is no point in continuing to multiply and add, because it will only increase. And if we haven't reached the goal yet, the function tries both possible paths starting with the given number. She summons herself twice, once with each method. If the first call does not return null, it is returned. In another case, the second one is returned.

To better understand how the function achieves its desired effect, let's look at the calls it makes to find a solution to the number 13.

Find(1, "1") find(6, "(1 + 5)") find(11, "((1 + 5) + 5)") find(16, "(((1 + 5) + 5 ) + 5)") too big find(33, "(((1 + 5) + 5) * 3)") too big find(18, "((1 + 5) * 3)") too big find( 3, "(1 * 3)") find(8, "((1 * 3) + 5)") find(13, "(((1 * 3) + 5) + 5)") found!

The indentation shows the depth of the call stack. The first time, the find function calls itself twice to check solutions starting with (1 + 5) and (1 * 3). The first call looks for a solution starting with (1 + 5) and uses recursion to check all solutions that produce a number less than or equal to the required number. Doesn't find it and returns null. Then the operator || and moves on to a function call that examines the (1 * 3) option. We're in luck here, because in the third recursive call we get 13. This call returns a string, and each of the || along the way it passes this line higher, resulting in returning a solution.

Growing Functions There are two more or less natural ways to introduce functions into a program.

The first is that you write similar code several times. This should be avoided - more code means more room for errors and more reading material for those trying to understand the program. So we take a recurring functionality, give it a good name, and put it into a function.

The second way is that you discover a need for some new functionality that is worthy of being placed in separate function. You start with the name of the function, and then write its body. You can even start by writing the code that uses the function before the function itself has been defined.

How difficult it is for you to name a function shows how well you understand its functionality. Let's take an example. We need to write a program that prints two numbers, the number of cows and chickens on the farm, followed by the words “cows” and “chickens.” You need to add zeros to the numbers in front so that each one occupies exactly three positions.

007 Cows 011 Chickens

Obviously, we need a function with two arguments. Let's start coding.
// print FarmInventory function printFarmInventory(cows, chickens) ( var cowString = String(cows); while (cowString.length< 3) cowString = "0" + cowString; console.log(cowString + " Коров"); var chickenString = String(chickens); while (chickenString.length < 3) chickenString = "0" + chickenString; console.log(chickenString + " Куриц"); } printFarmInventory(7, 11);

If we add .length to a string, we get its length. It turns out that the while loops add leading zeros to the numbers until they get a line of 3 characters.

Ready! But just as we were about to send the code to the farmer (along with a hefty check, of course), he calls and tells us that he has pigs on his farm, and could we add a display of the number of pigs to the program?

Of course it is possible. But when we start copying and pasting the code from these four lines, we realize that we need to stop and think. There must be a better way. We are trying to improve the program:

// output WITH Adding Zeros AND Labels function printZeroPaddedWithLabel(number, label) ( var numberString = String(number); while (numberString.length< 3) numberString = "0" + numberString; console.log(numberString + " " + label); } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { printZeroPaddedWithLabel(cows, "Коров"); printZeroPaddedWithLabel(chickens, "Куриц"); printZeroPaddedWithLabel(pigs, "Свиней"); } printFarmInventory(7, 11, 3);

Works! But the name printZeroPaddedWithLabel is a bit strange. It combines three things—output, adding zeros, and a label—into one function. Instead of inserting an entire repeating fragment into a function, let's highlight one concept:

// add Zero function zeroPad(number, width) ( var string = String(number); while (string.length< width) string = "0" + string; return string; } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { console.log(zeroPad(cows, 3) + " Коров"); console.log(zeroPad(chickens, 3) + " Куриц"); console.log(zeroPad(pigs, 3) + " Свиней"); } printFarmInventory(7, 16, 3);

A function with a nice, clear name zeroPad makes the code easier to understand. And it can be used in many situations, not only in our case. For example, to display formatted tables with numbers.

How smart and versatile should the features be? We can write a simple function that pads a number with zeros up to three positions, or a sophisticated general purpose function for formatting numbers that supports fractions, negative numbers, dot alignment, padding, etc.

A good rule of thumb is to add only functionality that you know will be useful. Sometimes it's tempting to create general-purpose frameworks for every little need. Resist him. You'll never finish the job, you'll just end up writing a bunch of code that no one will use.

Functions and Side Effects Functions can be roughly divided into those that are called for their side effects and those that are called to obtain some value. Of course, it is also possible to combine these properties in one function.

The first helper function in the farm example, printZeroPaddedWithLabel, is called because it has a side effect: it prints a string. The second, zeroPad, because of the return value. And it’s not a coincidence that the second function comes in handy more often than the first. Functions that return values ​​are easier to combine with each other than functions that produce side effects.

A pure function is a special kind of value-returning function that not only has no side effects, but also does not depend on the side effects of the rest of the code - for example, it does not work with global variables that could be accidentally changed somewhere else. A pure function, when called with the same arguments, returns the same result (and does nothing else) - which is quite nice. She's easy to work with. A call to such a function can be mentally replaced by the result of its work, without changing the meaning of the code. When you want to test such a function, you can simply call it, and be sure that if it works in a given context, it will work in any context. Less pure functions may return different results depending on many factors, and have side effects that are difficult to test and account for.

However, you should not be embarrassed to write functions that are not entirely pure, or to begin a sacred code cleansing of such functions. Side effects are often beneficial. There is no way to write a clean version of the console.log function, and this function is quite useful. Some operations are easier to express using side effects.

Summary This chapter showed you how to write your own functions. When keyword function is used as an expression and returns a pointer to the function call. When used as an instruction, you can declare a variable by assigning a function call to it.

The key to understanding functions is local scope. Parameters and variables declared inside a function are local to it, are recreated each time it is called, and are not visible from the outside. Functions declared inside another function have access to its scope.

It is very useful to separate the different tasks performed by a program into functions. You don't have to repeat yourself; functions make code more readable by dividing it into meaningful parts, just as chapters and sections of a book help organize regular text.

ExercisesMinimum In the previous chapter, we mentioned the Math.min function, which returns the smallest of its arguments. Now we can write such a function ourselves. Write a min function that takes two arguments and returns the minimum of them.

Console.log(min(0, 10)); // → 0 console.log(min(0, -10)); // → -10

Recursion We have seen that the % (modulo) operator can be used to determine whether a number (%2) is even. Here's another way to define it:

Zero is even.
The unit is odd.
Any number N has the same parity as N-2.

Write a recursive function isEven according to these rules. It must accept a number and return a boolean value.

Test it at 50 and 75. Try giving it -1. Why is she acting this way? Is it possible to somehow fix it?

Test it on 50 and 75. See how it behaves on -1. Why? Can you think of a way to fix this?

Console.log(isEven(50)); // → true console.log(isEven(75)); // → false console.log(isEven(-1)); // → ??

Counting the beans.

The character number N of a string can be obtained by adding .charAt(N) (“string”.charAt(5)) to it - in a similar way to getting the length of a string using .length. The return value will be a string consisting of one character (for example, “k”). The first character of the string has position 0, which means that the last character will have position string.length - 1. In other words, a string of two characters has length 2, and its character positions will be 0 and 1.

Write a function countBs that takes a string as an argument and returns the number of “B” characters contained in the string.

Then write a function called countChar, which works something like countBs, but takes a second parameter - the character we'll be looking for in the string (instead of just counting the number of "B" characters). To do this, rework the countBs function.



tell friends