How to set up smartphones and PCs. Informational portal
  • home
  • OS
  • Functional programming. Functions in JavaScript

Functional programming. Functions in JavaScript

Functions

Function is a block of JavaScript code that is defined once and can be executed, or called, multiple times. You may already be familiar with a function by another name, such as a subroutine or procedure. Functions can have parameters: a function definition can include a list of identifiers, which are called parameters and act as local variables in the body of the function.

When calling functions, they can be passed values ​​or arguments corresponding to their parameters. Functions often use their arguments to evaluate the return value, which is the value of the function call expression. In addition to arguments, when calling any function, another value is passed to it that determines the context of the call - the value in the keyword this.

Functions in JavaScript are objects and can be used in a variety of ways. For example, functions can be assigned to variables and passed on to other functions. Since functions are objects, it is possible to assign values ​​to their properties and even call their methods.

JavaScript allows you to create function definitions that are nested within other functions, and such functions will have access to all the variables present in the scope of the definition.

Defining functions

Function definition starts with a keyword function followed by the following components:

An identifier defining the name of the function

The name is a required part of the function declaration statement: it will be used to create a new variable to which the new function object will be assigned. The name can be absent in function definition expressions: if present, the name will refer to the function object only in the body of the function itself.

A pair of parentheses around a list of zero or more identifiers, separated by commas

These identifiers will define the names of the function parameters and can be used as local variables in the function body.

A pair of curly braces with zero or more JavaScript statements inside

These instructions make up the body of the function: they are executed each time the function is called.

The following example shows several function definitions as statements and expressions. Note that function definitions as expressions are only useful if they are part of larger expressions, such as assignments or function calls, that do something with a newly declared function:

// Prints the names and values ​​of all properties of the obj object function printprops (obj) (for (var p in obj) console.log (p + ":" + obj [p] + "\ n");) // Calculates the distance between points (x1, y1) and (x2, y2) function distance (x1, y1, x2, y2) (var dx = x2 - x1; var dy = y2 - y1; return Math.sqrt (dx * dx + dy * dy );) // Recursive function (calling itself) that calculates the factorial function factorial (x) (if (x

Note that the function name may not be present in the function definition expressions. A function declaration statement actually declares a variable and assigns a function object to it.

In contrast, a function definition expression does not declare a variable. However, in the definition expressions, it is allowed to specify the function name, as in the function for calculating the factorial above, which may be required in the body of the function to call itself. If the function definition expression includes a name, the given name will refer to the function object in the scope of that function. In fact, the name of the function becomes a local variable, accessible only in the body of the function. In most cases, the function name does not need to be specified in the definition expressions, which makes the definitions more compact.

Note that most (but not all) of the functions in the example contain a return statement. The return statement ends the execution of the function and returns the value of its expression (if specified) to the calling program. If there is no expression in the return statement, it returns undefined. If there is no return statement in the function, the interpreter will simply execute all statements in the function body and return undefined to the calling program.

Most of the functions in the example evaluate some value, and they use a return statement to return that value to the calling program. The printprops () function is slightly different in this sense: its job is to print out the names of the properties of an object. It doesn't need to return any value, so there is no return statement in the function. The printprops () function will always return undefined. (Functions that do not have a return value are sometimes called procedures.)

Calling functions

The program code that forms the body of the function is executed not at the moment the function is defined, but at the moment it is called. Function calls are performed using a call expression. A call expression consists of a function call expression that returns a function object, followed by parentheses followed by a list of zero or more argument expressions, separated by commas, inside.

If the function call expression is a property call expression - if the function is a property of an object or an element of an array (that is, a method) - then the call expression is a method call expression. The following snippet demonstrates several examples of ordinary function call expressions:

Printprops ((x: 4, age: 24)); var d = distance (1,1,5,6); var f = factorial (5) / factorial (12); f = square (5);

When the function is called, all argument expressions (specified between parentheses) are evaluated, and the resulting values ​​are used as arguments to the function. These values ​​are assigned to parameters whose names are listed in the function definition. In the body of a function, parameter call expressions return the values ​​of the corresponding arguments.

When a normal function is called, the return value of the function becomes the value of the calling expression. If the function returns when the interpreter reaches its end, the return value is undefined. If a function returns as a result of a return statement, the value of the expression following the return statement is returned, or undefined if the return statement has no expression.

Method is nothing more than a function that is stored as a property of an object. If you have a func function and an obj object, you can define a method on the obj object named method, as shown below:

// Define a simple object and function var obj = (); function func (a, b) (return a + b;) // Add the obj method to the obj object.method = func; // Now you can call this method var result = obj.method (4, 5);

Most often, when calling methods, you use the form of accessing properties using the dot operator, but in the same way you can use the form of accessing properties using square brackets. For example, both of the following expressions are method invocation expressions:

Result = obj.method (4, 5); result = obj ["method"] (4, 5);

The arguments and return value of a method call are handled in the same way as a regular function call. However, method invocation has one important difference: the invocation context. A property access expression consists of two parts: an object (in this case obj) and a property name (method). In such method call expressions, the obj object becomes the calling context, and the body of the function is able to refer to this object using the this keyword. For instance:

Var obj = (x: 0, y: 0, // Method add: function (a, b) (this.x = a; this.y = b;), // Another method sum: function () (return this.x + this.y)); // Calling methods obj.add (15, 4); console.log (obj.sum ()); // nineteen

Methods and the this keyword are central to the object-oriented programming paradigm. Any function used as a method actually receives an implicit argument - the object on which it was called. Typically, methods perform some action on an object, and the method call syntax clearly reflects the fact that a function operates on an object.

Note: this is just a keyword, not a variable or property name. JavaScript syntax does not allow assignment of values ​​to the this element.

Function arguments and parameters

In JavaScript, parameter types are not specified in function definitions, and no type checks are performed on the passed argument values ​​when functions are called. In fact, when calling functions in JavaScript, even the number of arguments is not checked. The subsections below describe what happens when the number of arguments in a function call is less than or more than the number of declared parameters. They also demonstrate how you can explicitly check the types of a function's arguments if you need to ensure that the function is not called with invalid arguments.

Optional Arguments

When the number of arguments in a function call is less than the number of declared parameters, the missing arguments are undefined. It is often convenient to write functions so that some of the arguments are optional and can be omitted when the function is called. In this case, it is desirable to provide for the possibility of assigning reasonably reasonable default values ​​to parameters that can be omitted. For instance:

// Add the enumerated names // of the properties of the obj object to the arr array and return it. If the argument // arr was not passed, create and return a new array function getPropertyNames (obj, / * optional * / arr) (if (arr === undefined) arr =; // If the array is not defined, create a new one for ( var property in obj) arr.push (property); return arr;) // This function can be called with 1 or 2 arguments: var a = getPropertyNames ((x: 1, y: 1)); // Get object properties in a new array getPropertyNames ((z: 5), a); // add properties of the new object to this array console.log (a); // ["x", "y", "z"]

Note that when declaring functions, optional arguments must end the argument list to be omitted. The programmer who will write a call to your function will not be able to pass the second argument and at the same time omit the first: he will be forced to explicitly pass undefined in the first argument. Notice also the comment / * optional * / in the function definition, which emphasizes the fact that the parameter is optional.

Variable-length argument lists

If the number of arguments in a function call exceeds the number of parameter names, the function is prevented from accessing unnamed values ​​directly. The solution to this problem provides Arguments object... In the body of the function, the identifier arguments refers to the Arguments object present in the call. The Arguments object is an array-like object that allows you to retrieve values ​​passed to a function by their numbers, rather than by name.

Suppose func has been defined that requires one argument, x. If you call this function with two arguments, then the first will be available inside the function by the name of the parameter x or as arguments. The second argument will only be available as arguments. In addition, like real arrays, arguments has a length property that determines the number of elements to contain. That is, in the body of func called with two arguments, arguments.length is 2.

The Arguments object can be used for a wide variety of purposes. The following example shows how to use it to check if a function was called with the correct number of arguments, as JavaScript won't do that for you:

Function func (x, y, z) (// First, it checks if the correct number of arguments was passed if (arguments.length! = 3) (throw new Error ("Function func was called with" + arguments.length + "arguments, but 3. ");) // And now the function code itself ...)

Note that it is often unnecessary to check the number of arguments, as in this example. The default behavior of the JavaScript interpreter is great for most cases: missing arguments are replaced with undefined, and extra arguments are simply ignored.

The Arguments object illustrates an important feature of JavaScript functions: they can be written to take any number of arguments. The following function takes any number of arguments and returns the value of the largest of them (the built-in Math.max () function behaves similarly):

Function maxNumber () (var m = Number.NEGATIVE_INFINITY; // Loop through all arguments, find and // store the largest of them for (var i = 0; im) m = arguments [i]; // Return the largest return m ;) var largest = maxNumber (1, 10, 100, 2, 3, 1000, 4, 5, 10000, 6); // 10000

Functions like this, which can take an arbitrary number of arguments, are called variadic functions, variable arity functions, or varargs functions. This term originated with the advent of the C programming language.

Note that functions with a variable number of arguments must not be callable with an empty argument list. It makes perfect sense to use the arguments object when writing a function that expects to receive a fixed number of required named arguments, followed by an arbitrary number of optional unnamed arguments.

Keep in mind that arguments are not actually an array - they are an Arguments object. Each Arguments object has numbered array elements and a length property, but technically it is not an array. Better to think of it as an object with some numbered properties.

In addition to the elements of its array, the Arguments object defines properties callee and caller... Attempting to change the values ​​of these properties in ECMAScript 5 strict mode is guaranteed to throw a TypeError exception. However, in lax mode, the ECMAScript standard states that the callee property refers to the currently executing function. The caller property is not standard, but it is present in many implementations and refers to the function that called the current one.

The caller property can be used to access the call stack, and the callee property is especially useful for recursively calling unnamed functions:

Var factorial = function (x) (if (x

Properties and methods of functions

We have seen that functions can be used as values ​​in JavaScript programs. The typeof operator returns the string "function" for functions, but functions in JavaScript are actually a special kind of object. And since functions are objects, they have properties and methods like any other object. There is even a Function () constructor that creates new function objects. The following subsections describe the properties and methods of functions.

Length property

In the body of the function, the arguments.length property determines the number of arguments passed to the function. However, the length property of the function itself has a different meaning. This read-only property returns the number of arguments the function expects to receive - the number of parameters declared.

The following snippet defines a function named check () that receives an array of arguments from another function. It compares the arguments.length property (the number of arguments actually passed) with the arguments.callee.length property (the number of arguments expected) to determine if the function has been passed as many arguments as it expects. If the values ​​do not match, an exception is thrown. The check () function is followed by the func () test function, which demonstrates how to use the check () function:

// This function uses arguments.callee, so it // won't work in strict mode function check (args) (var actual = args.length; // Actual number of arguments var expected = args.callee.length; // Expected number arguments if (actual! == expected) // If they do not match, throw new Error ("expected:" + expected + "; received" + actual);) function func (x, y, z) (// Check number of arguments expected and actually passed check (arguments); // Now execute the rest of the function return x + y + z;)

Prototype property

Any function has a prototype property that refers to an object known as a prototype object. Each function has its own prototype object. When a function is used as a constructor, the newly created object inherits the properties of that prototype object.

Prototypes and the prototype property were discussed in the previous article.

Call () and apply () methods

The call () and apply () methods allow you to indirectly call a function as if it were a method of some other object. The first argument to both call () and apply () is the object on which the function is called; this argument defines the context of the call and becomes the value of the this keyword in the body of the function. To call func () (with no arguments) as a method of obj, you can use either of the call () or apply () methods:

Func.call (obj); func.apply (obj);

Any of these call methods is equivalent to the following snippet (assuming that obj does not have a property named m):

Obj.m = func; // Temporarily make func the obj method obj.m (); // Call it with no arguments. delete obj.m; // Remove temporary method.

In ECMAScript 5 strict mode, the first argument of the call () and apply () methods becomes the this value, even if it is a simple value, null, or undefined. In ECMAScript 3 and non-strict mode, null and undefined values ​​are replaced by the global object, and the simple value is replaced by the corresponding wrapper object.

All other arguments to the call () method following the first argument that specifies the context of the call are passed to the called function. The apply () method acts like the call () method, except that the arguments to the function are passed as an array. If a function can handle an arbitrary number of arguments, the apply () method can be used to call that function in the context of an arbitrary length array.

The following example demonstrates a practical use of the call () method:

// Below are two functions that display properties and // property values ​​of an arbitrary object. The display method // are passed as an argument func function print1 (func, obj) (for (n in obj) func (n + ":" + obj [n]);) function print2 (func, objDevice, obj) (for ( n in obj) func.call (objDevice, n + ":" + obj [n]);) var obj = (x: 5, y: 10); print2 (document.write, document, obj); // Works correctly print2 (console.log, console, obj); print1 (document.write, obj); // An Illegal invocation exception will be thrown because print1 (console.log, obj); // it is impossible to call these methods without a context object

Bind () method

The bind () method first appeared in ECMAScript 5, but is easy to imitate in ECMAScript 3. As its name suggests, the main purpose of the bind () method is to bind a function to an object. If you call the bind () method of func and pass the obj object to it, it will return a new function. Calling the new function (like a normal function) will call the original func function as a method of obj. Any arguments passed to the new function will be passed to the original function. For instance:

// The function to bind function func (y) (return this.x + y;) var obj = (x: 1); // The object to bind to var g = func.bind (obj); // Calling g (x) will call obj.func (x)

This way of binding is easy to implement in ECMAScript 3, as shown below:

// Returns a function that calls func as a method of obj // and passes all of its arguments to it function bind (func, obj) (if (func.bind) return func.bind (obj); // Use bind method, if present else return function () (// Else bind like below return func.apply (obj, arguments););)

The bind () method in ECMAScript 5 doesn't just bind a function to an object. It also does partial application: in addition to the this value, all arguments passed to bind () after its first argument will be bound. Partial application is a common technique in functional programming and is sometimes called currying.

The article is under construction!

An article in which we will consider what a function is, as well as the traditional (classic) version of working with it. In addition, we will analyze what the arguments (parameters) of the function and the operator return are.

What is a function?

A function is some set of instructions which can be given a name and then refer to him by this name from anywhere in the program.

A classic example of using a function. The web page has JavaScript code, some fragment in which it is repeated several times... To avoid this you can shape this snippet as a function, a then call it in the right places in the code by the name of this function. Calling this function will mean following instructions located in it.

How can I organize the execution of some task in JavaScript using functions? To do this, they usually do this:

  • break the task into its component parts (subtasks);
  • subtasks are formalized through functions;
  • develop the main code using a call to the generated functions.

As a result, such a program becomes more structured. It is easier to make various changes and add new features to it.

Function declaration and call

Function operations in JavaScript can be divided into 2 steps:

  • declaration (creation) functions.
  • invocation (execution) this function.

Function declaration. Creating a function in JavaScript begins by writing the function keyword, followed by the name of the function, then in parentheses x, if necessary. the parameters are listed followed by instructions that are enclosed in curly braces.

// function declaration someName function someName () (alert ("You called the someName function!");) JavaScript - Function declaration syntax

Functions of this kind in JavaScript are called function declaration statement... In addition to this type, JavaScript also distinguishes functions function definition expression and arrow function expression.

Formation of a function name follows the same rules as a variable name. Those. it can contain letters, numbers (0-9), "$" and "_" signs. It is recommended to use only letters of the English alphabet (a-z, A-Z) as letters. The function name, as well as the variable name, cannot begin with a digit.

A function can have as many parameters as you like, or not at all. Parentheses are indicated in any case. If there are several parameters, then they must be separated among themselves using a comma. Function parameters are addressed by their name.

Instruction set, enclosed in curly braces is the function code that will be executed when it is called.

Function call. Declared function by her own will not be executed... In order to start it, you need to call it. The function is called by specifying its name and two parentheses. Arguments are provided within parentheses, if necessary.

// call the function given in the previous example someName (); JavaScript - Function Call Syntax

Is a function in JavaScript an object?

Functions in JavaScript are objects. In JavaScript, everything is generally an object, except for the six primitive data types. And if the function is an object, then a reference to it can be saved into a variable.

// function declaration someName function someName () (alert ("You called the someName function!");) var reference = someName;

After that, you can call the function like this:

Reference ();

Function parameters and arguments

Function arguments- these are the values ​​that are passed to the function at the stage of its call. Separate arguments from each other with a comma.

// call the sayWelcome function with two arguments passed to it sayWelcome ("Ivan", "Ivanov"); // another call to the sayWelcome function with two arguments sayWelcome ("Peter", "Petrov");

Function parameters Is one of the ways in JavaScript that you can refer to arguments within a function. The parameters of the function at the stage of its declaration are described in parentheses.

In other words function parameters- these are local variables that are created automatically at the stage of starting the function. As values, the parameters receive the corresponding arguments passed to the function at the time of its call. Parameters can be accessed only within this function, outside of it they do not exist.

// declaration of the sayWelcome function, which has two parameters function sayWelcome (userFirstName, userLastName) (// an instruction that displays the values ​​of the “userFirstName” and “userLastName” parameters to the console console.log ("Welcome," + userLastName + "" + userFirstName );)

In JavaScript, when calling a function the number of arguments does not have to be the same as the number of parameters... Parameters that were not set to a value when called will be undefined.

For example, let's call the function from the example above without specifying one or two parameters:

// call the sayWelcome function and pass one argument to it sayWelcome ("Peter"); // Welcome undefined Peter // call the sayWelcome function without passing arguments to it sayWelcome (); // Welcome, undefined undefined

An example of a function that will simply print the arguments passed to it to the browser console:

// function declaration function outputParam (param1, param2, param3) (console.log (param1 + ";" + param2 + ";" + param3);) // calls to the outputParam function with a different number of parameters passed to it outputParam ("Rain" , "Snow", "Fog"); // Rain; Snow; Fog outputParam (17); // 17; undefined; undefined outputParam (24.33); // 24; 33; undefined outputParam (); // undefined; undefined; undefined

Another way to refer to arguments within a function is to use the special arguments object. Arguments are accessed via arguments in the same way as elements of a regular array, i.e. by their serial numbers. Thus, argument is the first argument, arguments is the second, and so on.

// function declaration sum function sum (num1, num2) (/ * num1 or arguments - get the value of 1 of the argument num2 or arguments - get the value of 2 of the argument * / var sum1 = num1 + num2, sum2 = arguments + arguments; return "Sum, received by way 1 is equal to "+ sum1 +"; sum obtained by way 2 is equal to "+ sum2;) / * output the result of the sum function to the console 7 - the first argument (you can refer to it both by the name num1 and using arguments) 4 - the second argument (you can refer to it both by the name num2 and using arguments) * / console.log (sum (7,4));

The main difference between these methods is that the first of them allows you to access only those arguments that were named at the stage of the function declaration. The second method allows you to get the value of any argument, even if it has no name (by ordinal number). This feature of the JavaScript language allows you to create versatile flexible functions.

In addition to receiving arguments, the arguments object also lets you know how many arguments there are. This is done using the length property.

Iterate over arguments passed to the function, you can, for example, using a for or for ... of loop.

// function declaration sum function sum () (var i = 0; console.log ("Outputting all arguments using a for loop"); for (i; i< arguments.length; i++) { console.log(i + 1 + " аргумент равен " + arguments[i]); } console.log("Вывод всех аргументов с помощью цикла for...of"); for (arg of arguments) { console.log(arg); } } // вызов функции sum sum(7, 4, 3, 1);

A function that prints to the console all the arguments passed to it and their number:

// function declaration function myFunction () (var i; console.log ("Number of passed parameters =" + arguments.length); // iterate over all parameters using the for loop for (i = 0; i< arguments.length; i++) { console.log(i + " параметр = " + arguments[i]); } } // вызовы функции myFunction myFunction(3, 7, 27, "JavaScript"); myFunction(); myFunction("Яблоки", "Груши", "Апельсины");

A function that adds all the arguments passed to it (their number is not known in advance):

// function declaration var myCalc = function () (// iterate over all parameters using the for loop var i, sum = 0; for (i = 0; i lt; arguments.length; i ++) (sum + = arguments [i] ;) // return the sum as a result return sum;) // call the function (output to the console) console.log (myCalc (4, 20, 17, -6));

As a result, using the arguments object, you can implement in the body of the function:

  • checking the number of arguments passed;
  • how many parameters are processed.

In addition to the function itself, other functions that are in it also have access to the arguments that are passed to it at the call stage.

Function mainF (p1, p2) (function childF () (console.log ("p1 =" + p1 + "; p2 =" + p2);) childF ();) mainF (3, 5); // p1 = 3; p2 = 5 mainF (4, 7); // p1 = 4; p2 = 7

Default parameter value

Since ECMAScript 2015 (6) function parameter you can set the value that it will have by default.

For example, let's set the “color” parameter to its default value equal to “# 009688”:

Function setBGColor (color = "# 009688") (document.body.style.backgroundColor = color;) setBGColor (); // background color will be # 009688 setBGColor ("red"); // background color will be red

Before ECMAScript 2015, you could set a parameter to a default value, for example, it was like this:

Function setBGColor (color) (color = color! == undefined? Color: "# 009688"; // set the default color to "# 009688" document.body.style.backgroundColor = color;)

Rest parameters

If, when calling a function, you pass more arguments to it than it has parameters, then you can get the rest using the so-called rest patameters... This feature has appeared in the language since ECMAScript 2015.

// ... nums are the remaining parameters, which can be accessed in this case by the name nums function doMath (mathAction, ... nums) (var result = 0; nums.forEach (function (value) (switch (mathAction) ( case "sum": result + = value; break; case "sumCube": result + = value ** 3; break; case "sumSquare": result + = value ** 2; break; deafult: result = 0;)) ) return result;) console.log (doMath ("sum", 3, 4, 21, -4)); // 24 (3 + 4 + 21 + (-4)) console.log (doMath ("sumSquare", 1, 4)); // 17 (1 ^ 2 + 4 ^ 2) console.log (doMath ("sumCube", 3, 2, 4)); // 99 (3 ^ 3 + 2 ^ 3 + 4 ^ 3)

Return statement

The return statement is intended to return the value or the result of evaluating the expression of the current function. The value or expression must be separated from return by a space. In addition, the return statement terminates the execution of the function, i.e. all instructions following it will not be executed.

A JavaScript function always returns a result, regardless of whether the return statement is used or not.

// function that returns the result function sayWelcome (userFirstName, userLastName) (if ((! userFirstName) || (! userLastName)) return "Welcome, anonymous user"; else return "Welcome," + userLastName + "" + userFirstName ;) // variable declaration person var person; // assign the result of the function sayWelcome to the person variable person = sayWelcome ("Ivan", "Ivanov"); // print the value of the variable to the console console.log (person); // An instruction that will print to the console the result of the sayWelcome function console.log (sayWelcome ("Peter", "Petrov")); // An instruction that will print to the console the result of the function sayWelcome console.log (sayWelcome ("Sidorov")); JavaScript - Function with parameter validation

A JavaScript function, as a result of its execution, always returns a result, even if it is not explicitly defined using the return statement. This result is undefined.

// 1. a function that does not return any result function sayWelcome (userFirstName, userLastName) (console.log ("Welcome," + userLastName + "" + userFirstName);) // try to get the result from a function that does not return anything console .log (sayWelcome ("Ivan", "Ivanov")); // 2. a function containing a return statement without a value function sayDay (day) (day = "Today," + day; return; // this statement will not be executed, because it comes after the return statement console.log (day) ;) // try to get the result from a function that contains a return statement without a value console.log (sayDay ("February 21, 2016")); JavaScript - Get a value from a function that returns nothing

The same result will be obtained if you do not specify a return value for the return statement.

Function overloading in JavaScript

Function overloading in programming is the ability to declare multiple functions with the same name in the same scope. Such functions differ from each other in the type and number of arguments. Each function has its own program logic. Function overloading is used so that similar actions can be performed using a single function name.

JavaScript does not support function overloading as it is, for example, in C-like languages. Those. JavaScript cannot create multiple functions with the same name in the same scope.

Similar functionality can be implemented in JavaScript using the following steps:

  • In order to check if an argument is passed or not, use a condition with checking its value for undefined.
  • Use the object's arguments length property to check the number of arguments passed to a function.
  • Use the typeof or instanceof operators to find out the type of the passed argument value.
  • To work with a variable number of arguments, use the arguments object.
  • Starting in ECMAScript6, you can provide default values ​​for arguments.

For example, let's create a function that can be called with one or two arguments:

// declaration of a function that changes the background color of elements function setBgColor (bgColor, elements) (// if the elements parameter is not specified when calling if (elements === undefined) (// then equate its value "div" elements = "div ";) // get all elements elements = $ (elements); // iterate over all elements and set them to the specified background color elements.each (function () ($ (this) .css (" background-color ", bgColor) ;));) / * Call the setBgColor function with one parameter. Because 2 parameter is not specified, then this function will change the background color of all div elements. * / SetBgColor ("green"); / * Call the setBgColor function with 2 parameters. Because 2 parameter is specified, then this function will change the background color of only button elements. * / SetBgColor ("# ff0000", "button");

Let's make some changes to the above code. Namely, let us specify the default value for the second parameter:

// declaring a function that changes the background color of elements // the elements parameter is set to "div" by default function setBgColor (bgColor, elements = "div") (// get all elements elements = $ (elements); // iterate over all elements and set them to the specified background color elements.each (function () ($ (this) .css ("background-color", bgColor);));) // call the setBgColor function, specifying one parameter setBgColor ("green" ); // call the setBgColor function, specifying 2 parameters setBgColor ("# ff0000", "button");

An example of how in JavaScript you can implement an "overloaded" function that calculates the number of calories a person needs per day:

// function description function countCal (sex, height) (// parameters: sex (gender) and height (height) var result; if ((sex === 0) || (sex === "man")) ( result = (height - 100) * 20;) else if ((sex === 1) || (sex === "woman")) (result = (height - 105) * 19;) if (result) ( // arguments - activity level if (arguments) (result * = arguments;) console.log ("Number of kcal for normal life:" + result);) else (console.log ("Invalid parameters are specified");)) / * call a function and pass 2 arguments to it (1 is "man", it can be accessed using the name sex and arguments; 2 is the value 185, it can be accessed using the name sex and arguments) * / countCal ("man", 185); / * calling the function and passing it 3 parameters, although there are only 2 in the function description (in this case, you can get the value of 3 parameters only as arguments) * / countCal (0, 185, 2);

Recursion

Recursion is a call inside the body of some function to itself.

A function call is usually carried out depending on how it is declared by name or through a variable containing a reference to this function.

Function fact (n) (if (n === 1) (return 1;) return fact (n-1) * n;) console.log (fact (5)); // 120

You can call a function inside its body not only by name, but also using the callee property of the arguments object. But it is better not to use this property, because it is obsolete. In addition, in strict mode, it does not work at all.

What are built-in (standard) functions?

JavaScript has a huge set of built-in (standard) functions. These functions are already described in the browser engine itself. Almost all of them are methods of an object.

For example, in order to call the alert built-in function (method), it does not need to be declared in advance. It is already described in the browser. The alert method is called by specifying a name, parentheses, and an argument within them. This method is designed to display a message on the screen in the form of a dialog box. The text message is taken from the parameter value of this function.

// call the function alert alert ("Some text"); JavaScript - Calling the alert function

Functions are one of the fundamental building blocks in JavaScript. A function is a JavaScript procedure-a set of statements that performs a task or calculates a value. To use a function, you must define it somewhere in the scope from which you wish to call it.

A method is a function that is a property of an object. Read more about objects and methods in Working with objects.

Calling functions

Defining a function does not execute it. Defining the function simply names the function and specifies what to do when the function is called. Calling the function actually performs the specified actions with the indicated parameters. For example, if you define the function square, you could call it as follows:

Square (5);

The preceding statement calls the function with an argument of 5. The function executes its statements and returns the value 25.

Functions must be in scope when they are called, but the function declaration can be hoisted (appear below the call in the code), as in this example:

Console.log (square (5)); / * ... * / function square (n) (return n * n;)

The scope of a function is the function in which it is declared, or the entire program if it is declared at the top level.

Note: This works only when defining the function using the above syntax (i.e. function funcName () ()). The code below will not work. That means, function hoisting only works with function declaration and not with function expression.

Console.log (square); // square is hoisted with an initial value undefined. console.log (square (5)); // TypeError: square is not a function var square = function (n) (return n * n;)

The arguments of a function are not limited to strings and numbers. You can pass whole objects to a function. The show_props () function (defined in) is an example of a function that takes an object as an argument.

A function can call itself. For example, here is a function that computes factorials recursively:

Function factorial (n) (if ((n === 0) || (n === 1)) return 1; else return (n * factorial (n - 1));)

You could then compute the factorials of one through five as follows:

Var a, b, c, d, e; a = factorial (1); // a gets the value 1 b = factorial (2); // b gets the value 2 c = factorial (3); // c gets the value 6 d = factorial (4); // d gets the value 24 e = factorial (5); // e gets the value 120

There are other ways to call functions. There are often cases where a function needs to be called dynamically, or the number of arguments to a function vary, or in which the context of the function call needs to be set to a specific object determined at runtime. It turns out that functions are, themselves, objects, and these objects in turn have methods (see the Function object). One of these, the apply () method, can be used to achieve this goal.

Function scope

Variables defined inside a function cannot be accessed from anywhere outside the function, because the variable is defined only in the scope of the function. However, a function can access all variables and functions defined inside the scope in which it is defined. In other words, a function defined in the global scope can access all variables defined in the global scope. A function defined inside another function can also access all variables defined in its parent function and any other variable to which the parent function has access.

// The following variables are defined in the global scope var num1 = 20, num2 = 3, name = "Chamahk"; // This function is defined in the global scope function multiply () (return num1 * num2;) multiply (); // Returns 60 // A nested function example function getScore () (var num1 = 2, num2 = 3; function add () (return name + "scored" + (num1 + num2);) return add ();) getScore (); // Returns "Chamahk scored 5"

Scope and the function stack

Recursion

A function can refer to and call itself. There are three ways for a function to refer to itself:

  1. the function "s name
  2. an in-scope variable that refers to the function

For example, consider the following function definition:

Var foo = function bar () (// statements go here);

Within the function body, the following are all equivalent:

  1. bar ()
  2. arguments.callee ()
  3. foo ()

A function that calls itself is called a recursive function... In some ways, recursion is analogous to a loop. Both execute the same code multiple times, and both require a condition (to avoid an infinite loop, or rather, infinite recursion in this case). For example, the following loop:

Var x = 0; while (x< 10) { // "x < 10" is the loop condition // do stuff x++; }

can be converted into a recursive function and a call to that function:

Function loop (x) (if (x> = 10) // "x> = 10" is the exit condition (equivalent to "! (X< 10)") return; // do stuff loop(x + 1); // the recursive call } loop(0);

However, some algorithms cannot be simple iterative loops. For example, getting all the nodes of a tree structure (e.g. the DOM) is more easily done using recursion:

Function walkTree (node) (if (node ​​== null) // return; // do something with node for (var i = 0; i< node.childNodes.length; i++) { walkTree(node.childNodes[i]); } }

Compared to the function loop, each recursive call itself makes many recursive calls here.

It is possible to convert any recursive algorithm to a non-recursive one, but often the logic is much more complex and doing so requires the use of a stack. In fact, recursion itself uses a stack: the function stack.

The stack-like behavior can be seen in the following example:

Function foo (i) (if (i< 0) return; console.log("begin: " + i); foo(i - 1); console.log("end: " + i); } foo(3); // Output: // begin: 3 // begin: 2 // begin: 1 // begin: 0 // end: 0 // end: 1 // end: 2 // end: 3

Nested functions and closures

You can nest a function within a function. The nested (inner) function is private to its containing (outer) function. It also forms a closure... A closure is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).

Since a nested function is a closure, this means that a nested function can "inherit" the arguments and variables of its containing function. In other words, the inner function contains the scope of the outer function.

  • The inner function can be accessed only from statements in the outer function.
  • The inner function forms a closure: the inner function can use the arguments and variables of the outer function, while the outer function cannot use the arguments and variables of the inner function.

The following example shows nested functions:

Function addSquares (a, b) (function square (x) (return x * x;) return square (a) + square (b);) a = addSquares (2, 3); // returns 13 b = addSquares (3, 4); // returns 25 c = addSquares (4, 5); // returns 41

Since the inner function forms a closure, you can call the outer function and specify arguments for both the outer and inner function:

Function outside (x) (function inside (y) (return x + y;) return inside;) fn_inside = outside (3); // Think of it like: give me a function that adds 3 to whatever you give // ​​it result = fn_inside (5); // returns 8 result1 = outside (3) (5); // returns 8

Preservation of variables

Notice how x is preserved when inside is returned. A closure must preserve the arguments and variables in all scopes it references. Since each call provides potentially different arguments, a new closure is created for each call to outside. The memory can be freed only when the returned inside is no longer accessible.

This is not different from storing references in other objects, but is often less obvious because one does not set the references directly and cannot inspect them.

Multiply-nested functions

Functions can be multiply-nested, i.e. a function (A) containing a function (B) containing a function (C). Both functions B and C form closures here, so B can access A and C can access B. In addition, since C can access B which can access A, C can also access A. Thus, the closures can contain multiple scopes; they recursively contain the scope of the functions containing it. This is called scope chaining... (Why it is called "chaining" will be explained later.)

Consider the following example:

Function A (x) (function B (y) (function C (z) (console.log (x + y + z);) C (3);) B (2);) A (1); // logs 6 (1 + 2 + 3)

In this example, C accesses B "s y and A" s x. This can be done because:

  1. B forms a closure including A, i.e. B can access A "s arguments and variables.
  2. C forms a closure including B.
  3. Because B "s closure includes A, C" s closure includes A, C can access both B and A "s arguments and variables. In other words, C chains the scopes of B and A in that order.

The reverse, however, is not true. A cannot access C, because A cannot access any argument or variable of B, which C is a variable of. Thus, C remains private to only B.

Name conflicts

When two arguments or variables in the scopes of a closure have the same name, there is a name conflict... More inner scopes take precedence, so the inner-most scope takes the highest precedence, while the outer-most scope takes the lowest. This is the scope chain. The first on the chain is the inner-most scope, and the last is the outer-most scope. Consider the following:

Function outside () (var x = 5; function inside (x) (return x * 2;) return inside;) outside () (10); // returns 20 instead of 10

The name conflict happens at the statement return x and is between inside "s parameter x and outside" s variable x. The scope chain here is (inside, outside, global object). Therefore inside "s x takes precedences over outside" s x, and 20 (inside "s x) is returned instead of 10 (outside" s x).

Closures

Closures are one of the most powerful features of JavaScript. JavaScript allows for the nesting of functions and grants the inner function full access to all the variables and functions defined inside the outer function (and all other variables and functions that the outer function has access to). However, the outer function does not have access to the variables and functions defined inside the inner function. This provides a sort of encapsulation for the variables of the inner function. Also, since the inner function has access to the scope of the outer function, the variables and functions defined in the outer function will live longer than the duration of the outer function execution, if the inner function manages to survive beyond the life of the outer function. A closure is created when the inner function is somehow made available to any scope outside the outer function.

Var pet = function (name) (// The outer function defines a variable called "name" var getName = function () (return name; // The inner function has access to the "name" variable of the outer // function) return getName; // Return the inner function, thereby exposing it to outer scopes) myPet = pet ("Vivie"); myPet (); // Returns "Vivie"

It can be much more complex than the code above. An object containing methods for manipulating the inner variables of the outer function can be returned.

Var createPet = function (name) (var sex; return (setName: function (newName) (name = newName;), getName: function () (return name;), getSex: function () (return sex;), setSex: function (newSex) (if (typeof newSex === "string" && (newSex.toLowerCase () === "male" || newSex.toLowerCase () === "female")) (sex = newSex;)) )) var pet = createPet ("Vivie"); pet.getName (); // Vivie pet.setName ("Oliver"); pet.setSex ("male"); pet.getSex (); // male pet.getName (); // Oliver

In the code above, the name variable of the outer function is accessible to the inner functions, and there is no other way to access the inner variables except through the inner functions. The inner variables of the inner functions act as safe stores for the outer arguments and variables. They hold "persistent" and "encapsulated" data for the inner functions to work with. The functions do not even have to be assigned to a variable, or have a name.

Var getCode = (function () (var apiCode = "0] Eal (eh & 2"; // A code we do not want outsiders to be able to modify ... return function () (return apiCode;);)) () ; getCode (); // Returns the apiCode

There are, however, a number of pitfalls to watch out for when using closures. If an enclosed function defines a variable with the same name as the name of a variable in the outer scope, there is no way to refer to the variable in the outer scope again.

Var createPet = function (name) (// The outer function defines a variable called "name". Return (setName: function (name) (// The enclosed function also defines a variable called "name". Name = name; // How do we access the "name" defined by the outer function?)))

Using the arguments object

The arguments of a function are maintained in an array-like object. Within a function, you can address the arguments passed to it as follows:

Arguments [i]

where i is the ordinal number of the argument, starting at zero. So, the first argument passed to a function would be arguments. The total number of arguments is indicated by arguments.length.

Using the arguments object, you can call a function with more arguments than it is formally declared to accept. This is often useful if you don "t know in advance how many arguments will be passed to the function. You can use arguments.length to determine the number of arguments actually passed to the function, and then access each argument using the arguments object.

For example, consider a function that concatenates several strings. The only formal argument for the function is a string that specifies the characters that separate the items to concatenate. The function is defined as follows:

Function myConcat (separator) (var result = ""; // initialize list var i; // iterate through arguments for (i = 1; i< arguments.length; i++) { result += arguments[i] + separator; } return result; }

You can pass any number of arguments to this function, and it concatenates each argument into a string "list":

// returns "red, orange, blue," myConcat (",", "red", "orange", "blue"); // returns "elephant; giraffe; lion; cheetah;" myConcat (";", "elephant", "giraffe", "lion", "cheetah"); // returns "sage. basil. oregano. pepper. parsley." myConcat (".", "sage", "basil", "oregano", "pepper", "parsley");

Note: The arguments variable is "array-like", but not an array. It is array-like in that it has a numbered index and a length property. However, it does not possess all of the array-manipulation methods.

Two factors influenced the introduction of arrow functions: shorter functions and non-binding of this.

Shorter functions

In some functional patterns, shorter functions are welcome. Compare:

Var a = ["Hydrogen", "Helium", "Lithium", "Beryllium"]; var a2 = a.map (function (s) (return s.length;)); console.log (a2); // logs var a3 = a.map (s => s.length); console.log (a3); // logs

No separate this

Until arrow functions, every new function defined its own value (a new object in the case of a constructor, undefined in function calls, the base object if the function is called as an "object method", etc.). This proved to be less than ideal with an object-oriented style of programming.

Function Person () (// The Person () constructor defines `this` as itself.this.age = 0; setInterval (function growUp () (// In nonstrict mode, the growUp () function defines` this` // as the global object, which is different from the `this` // defined by the Person () constructor.this.age ++;), 1000);) var p = new Person ();

In ECMAScript 3/5, this issue was fixed by assigning the value in this to a variable that could be closed over.

Function Person () (var self = this; // Some choose `that` instead of` self`. // Choose one and be consistent.self.age = 0; setInterval (function growUp () (// The callback refers to the `self` variable of which // the value is the expected object.self.age ++;), 1000);)

Any programmer is well aware of what functions are and why they are needed. However, functions in Javascript have a few quirks. If you have been programming in this particular language for a long time, then you probably know that there are different ones. If you come from another language, then while reading some of the articles, you most likely saw this, at first glance, strange declaration of a function:

Var add = function (arg1, arg2) (var sum = arg1 + arg2; return sum;) var result = add (5, 2); // result is now 7

That is, the function, first of all, has no name. Secondly, it is assigned to a variable, but not just assigned, but its body immediately goes. Personally, for me, who had previously written in languages ​​such as VB, C ++, such a declaration caused bewilderment and misunderstanding of how it works and why write it like that at all.

I'm used to the "classic" function declaration and call, like this:

Function add (arg1, arg2) (var sum = arg1 + arg2; return sum;) var result = add (5, 3); // result is now 8

And this is where we come to the peculiarities of functions in Javascript. For ease of understanding, imagine that a function in JS is an ordinary value, such as a number or a string. Can you write the number 5 to the result variable? Or something more complex, like an array, and then display it on the screen? You can. So, if we imagine that a function is an ordinary value, albeit a very complex structure, then the first way of declaring it no longer seems like something incredible.

The next interesting fact is a logical continuation of the first one. After we put the data into a variable, we can transfer the data to another variable through the name of this variable:

Var a = 5; var b = a; alert (b); // will print 5

The usual thing. Now take a look at this code:

Var add = function (arg1, arg2) (var sum = arg1 + arg2; return sum;) var calcSum = add; alert (calcSum (5, 6)); // prints 11

Are you already starting to guess? Since a function is like a variable, we can "multiply" it by means of ordinary assignment into other variables, turning them into functions as well. Now calcSum can add two numbers too. However the code

Var calcSum = add (1, 1); // calcSum is now equal to 2, this is not a function, but a variable with a number alert (calcSum (5, 6)); //error

It will not be executed, because in the first line we assigned not the function itself, but the result of its execution (parentheses indicate that we need to execute the function, not assign it).

If you need to call a function in itself, then this is done as follows:

Var calcFact = function fact (val) (if (val == 1)? Val: val * fact (val - 1); // calculating the factorial using recursion) alert (calcFact (4)); // prints 24

Here, by assigning a function to a variable, we have given it the name fact. However, this name will only be available inside the function itself and nowhere else. The reasons for this lie in the principle of the interpreter and are beyond the scope of the lesson.

You may be wondering, "Hmm, an interesting opportunity! But what is the advantage of this method? Are there situations when it cannot be done without it, or is it at least more convenient than a regular ad?" I will not undertake to argue that there are situations where such an approach cannot be dispensed with, but I can give an example where it reduces the amount of code. Let's say you need to greet a person depending on the time of day:

Var date = new Date (); var hello = (date.getHours ()< 12) ? function() {alert("Доброе утро!")} : (date.getHours() < 18) ? function() {alert("Добрый день!")} : function() {alert("Добрый вечер!")}; hello();

As you can see, the functions are extremely simple, with a single alert command.

If we decided to go the "classic way", then we would have to write three separate functions, and then call them in a time check condition:

Function goodMorning () (alert ("Good morning!");) Function goodAfternoon () (alert ("Good afternoon!");) Function goodEvning () (alert ("Good evening!");) Var date = new Date (); (date.getHours ()< 12) ? goodMorning() : (date.getHours() < 18) ? goodAfternoon() : goodEvning();

The code has grown significantly visually, even considering that we used a short form of notation for the conditional operator. If we assume that the file contains really important functions that perform calculations, then littering the list with such mini-functions that do not carry important logic, and which are used, most likely, only once, is not a good idea. In addition, we are forced to give each function a unique name and indicate it when calling. Therefore, if you need to change the name of one of them, you will have to change it in two places, which increases the likelihood of an error.

Secondly, if we use the "classic" method, then we lose the ability to assign a function to a variable. That is, write

Function add (a, b) (return a + b;) var calcSum = add; calcSum (5, 5);

It's no longer possible. Therefore, in our example, if we still need to greet the guest more than once, we will have to duplicate this fragment each time:

(date.getHours ()< 12) ? goodMorning() : (date.getHours() < 18) ? goodAfternoon() : goodEvning();

And in the first case, it will be enough to write just hello (); and the result will be the same.

I told you about an interesting feature of JS functions and gave examples. So you saw that ways to call functions in Javascript are not limited to one single species. Even if you cannot immediately find application for these opportunities in your projects, at least you will know that there are such opportunities. And when the really good luck comes along, you can reduce the amount of code and avoid unnecessary confusion and errors!

This article describes Javascript language-level functions: creation, parameters, tricks, closures, and more.

Creating functions

There are 3 ways to create a function. The main difference as a result of their work is that the named function is visible everywhere, and the anonymous one is visible only after the declaration:

Functions - objects

In javascript, functions are full-fledged objects of the built-in Function class. That is why they can be assigned to variables, passed and, of course, they have properties:

Function f () (...) f.test = 6 ... alert (f.test) // 6

Function properties are also available inside the function, so they can be used as static variables.

For instance,

Function func () (var funcObj = arguments.callee funcObj.test ++ alert (funcObj.test)) func.test = 1 func () func ()

At the start, each function creates an arguments variable within itself and assigns arguments.callee a reference to itself. So arguments.callee.test is a property of func.test, i.e. the static variable test.

In the example, the assignment could not be made:

Var test = arguments.callee.test test ++

since in this case the ++ operation would have worked on the local variable test, and not on the test property of the function object.

The arguments object also contains all the arguments and can be converted to an array (although it is not), see below in the section on parameters.

Scopes

Each function, or rather even each launch of a function, sets its own individual scope.

Variables can be declared anywhere. The var keyword sets a variable in the current scope. If you forget it, then the variable will go to the global window object. Unexpected intersections with other window variables, conflicts and glitches are possible.

Unlike a number of languages, blocks do not define a separate scope. It makes no difference whether a variable is defined inside the block or outside it. So these two snippets are perfectly equivalent:

A variable specified via var is visible everywhere in scope, even before the var statement. For example, let's make a function that will change the variable, var for which is located below.

For instance:

Function a () (z = 5 // change z locally .. // .. because z is declared via var var z) // test delete z // clear the global za () just in case alert (window.z) // => undefined because z was changed locally

Function parameters

Functions can be run with any number of parameters.

If fewer parameters are passed to the function than there are in the definition, then the missing ones are considered undefined.

The following function returns the time required to cover distance distance with uniform speed speed.

On first launch, the function works with arguments distance = 10, speed = undefined. Typically, this situation, if supported by the function, provides a default value:

// if speed is a false value (undefined, 0, false ...) - substitute 10 speed = speed || 10

Operator || in javascript it does not return true / false, but the value itself (the first one, which is cast to true).

Therefore, it is used to set the default values. In our call, speed will be undefined || 10 = 10.

Therefore, the result will be 10/10 = 1.

The second launch is standard.

The third run gives several additional arguments. The function does not provide for working with additional arguments, so they are simply ignored.

Well, in the latter case, there are no arguments at all, so distance = undefined, and the result of the division is undefined / 10 = NaN (Not-A-Number, an error occurred).

Working with an indefinite number of parameters

Just before entering the body of the function, an arguments object is automatically created that contains

  1. Call arguments starting at zero
  2. The length in the length property
  3. A reference to the function itself in the callee property

For instance,

Function func () (for (var i = 0; i

The arguments property is like an array in that it has a length and numeric indices. In fact, arguments does not belong to the Array class and does not contain its methods such as push, pop, and others.

If you still want to use these methods, for example, to call another function with the same arguments, but besides the first one, you can create a real array from arguments:

Var args = Array.prototype.slice.call (arguments) // .. now args is a real array of arguments .. args.shift () ...

You can call a function on an array of arguments using apply:

Var func = function (a, b) (alert (a + b)) var arr = func.apply (null, arr) // => alert (3)

An example of passing a function by reference

A function can easily be passed as an argument to another function.

For example, map takes the function func, applies it to each element in the arr array, and returns the resulting array:

Var map = function (func, arr) (var result = for (var i = 0; i

Usage example:

Map (run,) // =

Or, you can create an anonymous function directly in the call to map:

// anonymous function triples the numbers map (function (a) (return a * 3),) // =

Folding parameters into an object

There are functions whose arguments vary greatly.

For instance:

// you can specify only a part of the arguments // not specified - are calculated or taken by default function resize (toWidth, toHeight, saveProportions, animate) (// default values ​​saveProportions = saveProportions || true animate = animate || true toHeight = toHeight | | ...)

A call with optional parameters has to be done like this:

Resize (100, null, null, true)

To avoid unnecessary nulls and make the code more readable, use something like the "keyword arguments" that exist in Python and Ruby. For this, many parameters are packed into a single object:

Function resize (setup) (// default values ​​var saveProportions = setup.saveProportions || true var animate = setup.animate || true var toHeight = setup.toHeight || ...)

The call is now much easier:

Var setup = (toWidth: 100, animate: true) resize (setup) // or resize ((toWidth: 100, animate: true))

So - much clearer. And if there are more than 5 parameters, then in general - the only normal way.

In addition, it is more convenient to make a sequence of calls with an object like:

Var setup = (toWidth: 100, animate: true, saveProportions: false) resize (setup) setup.toWidth = 200 resize (setup)

Top related articles