PS-Studio.info

Веб и веб-технологии

ABC 28.02.2020 в 15:29

Функции в JavaScript: а вот теперь начинается самое интересное!

Итак, основной синтаксис функции следующий:

Код
function имя функции() {
  здесь код, который необходимо выполнить
}


Создание новой функции начинается с ключевого слова function, сразу после которого пишется имя функции (при выборе имени функции руководствуйтесь теми же правилами, что и при выборе имён переменых, при этом старайтесь, чтобы имя функции также отражало суть её работы, что делает эта функция).

После имени функции идут круглые скобки, а затем фигурные, в которых размещается код, который необходимо выполнить.

Напишем пример простой функции:

Код
function showMessage() {
  alert('А это - результат работы функции!');
}


мы создали функцию с именем showMessage, которая при её запуске выполняет код в фигурных скобках, а именно: выводит модальное окно с текстом "А это - результат работы функции!"

Важный момент для понимания: сразу после создания функции не происходит никаких действий, не выполняется никакого кода, функция не начинает работу сама по себе.

А как запустить функцию, чтобы она заработала? Запустить, а правильнее говорить, вызвать функцию , можно, просто обратившись к ней по имени, сразу после которого добавить круглые скобки:

Код
showMessage();




а для чего вообще нужны эти самые круглые скобки, спросите вы?

Давайте внимательно посмотрим на ту функцию, что мы создали ранее. Что она умеет делать, так сказать? Она умеет создавать модальное окно с текстом "А это - результат работы функции!" Здорово? Ещё бы. Но только с этим текстом!
А если бы нам потребовалось в модальном окне вывести, к примеру, другой текст, например, знаменитую фразу "Hello,World!" Как быть в этом случае? Неужели создавать еще одну функцию?

Нет! Функция у нас уже есть, нам осталось только подсказать ей, что нужно поменять текст в окне! А как это сделать?

Тут то нам и пригодятся круглые скобки, вызывая функцию, после её имени в круглых скобках вы можете поместить информацию (или аргумент), которая передаётся в круглые скобки в параметр функции (переменную). Это называется передачей аргумента функции.
То есть, по сути, мы присваиваем значение переменной. После чего это значение используется в коде функции.

В связи с вышесказанным, перепишем нашу функцию:

Код

function showMessage(text) {
  alert(text);
}


в качестве параметра функции мы задали переменную, назвали её text, теперь при вызове функции в модальном окне будет выводиться содержимое переменной text.

А содержимое для этой переменной мы передадим, вызывая функцию, вот так:

Код
showMessage('Hello, World!');


и получаем на странице наш результат:



Как это получилось? При вызове функции, мы передали строку 'Hello, World!' (в качестве аргумента) и она сохранилась в параметр функции (переменную text), далее значение этой переменной подставилось в метод alert(), в результате чего в модальном окне появилась эта строка.
Вот такой принцип: создать единожды, использовать многократно.

К слову сказать, число параметров функции, также как и число аргументов, не ограничено единственным числом.

Код
function имяФункции (параметр1, параметр2, параметр3) {
  выполняемый функцией код  
}


вызывается функция с тем же количеством аргументов и в том же порядке, при этом аргумент1 сохраняется в параметр1, аргумент2 в параметр2 и так далее:

Код
имяФункции(аргумент1, аргумент2, аргумент3);


Например, мы хотим, чтобы наше приветствие "Hello, World" вывелось на странице, да еще в тегах div. Присвоим для начала нашей функции два параметра text и tag и заменим метод alert() на document.write(), чтобы вывести сообщение не в модальное окно, а на страницу сайта:

Код
function showMessage(text, tag) {
  document.write('<' + tag + '>' + text + '</' + tag + '>');
  }


а теперь вызовем нашу функцию, используя два аргумента:

Код
showMessage('Hello, World!' , 'div');


строка 'Hello, World!' сохранится в переменную text, а строка 'div' в переменную tag, а так как вместо имён переменных можно использовать их значения, то в коде в фигурных скобках фактически будет следующее:

Код
document.write('<' + 'div' + '>' + 'Hello, World!' + '</' + 'div' + '>');


для наглядности я добавил для тега div css-стили, чтобы вы увидели, что сообщение вывелось внутри тега div

Код
div {
  padding: 20px;
  background-color: #080808;
  color: #fff;
}


на странице сайта мы увидим



Запрос данных от функции и возвращаемое ею значение

Помимо функций, которые создаёте вы сами, существуют так называемые встроенные функции в языке JavaScript. Примером таких функций является та самая команда prompt(), которую мы неоднократно использовали ранее.

Код
let userName = prompt('Как Вас зовут?', ' ');


Функция prompt() возвращает то значение, которое пользователь вводит в модальном окне. В данном примере возвращаемое значение сохраняется в переменной userName, и мы можем его после этого как-то использовать.

Если нужно получить от функции какие-то данные (результат её работы), воспользуйтесь ключевым словом return, после которого укажите то, что хотите вернуть.
При этом, return в коде функции должно размещаться последней строкой, потому что интерпретатор JavaScript, встретив в коде это ключевое слово, выходит из функции, код в функции, размещённый после return, не выполнится.

Разберём на примере расчёта стоимости покупки, включающей НДС:

Код

let NDS = 0.18;
function calculateTotal(price,number) {
  let total = price * number * (1 + NDS);
  let totalFormatted = total.toFixed(2);
  return totalFormatted;
}


В первой строке кода в переменной NDS сохранено процентное значение НДС, равное 0.18. Далее мы объявляем функцию с двумя параметрами price и number, это параметры, которые в качестве аргументов при вызове функции будут принимать значения цены товара и его количества соответственно.

Что в самой функции: в переменную total мы сохраняем общую стоимость покупки, а в переменную totalFormatted её отформатированное значение (метод toFixed() форматирует число, в данном случае запись toFixed(2) даст нам два знака после запятой).

Ну и последней строкой мы возвращаем значение, сохранённое в переменной totalFormatted.

Создадим новую переменную и сохраним в неё результат вызова нашей функции:

Код
let saleTotal = calculateTotal(2500, 5);


а теперь выведем то, что сохранено в переменной saleTotal, на страницу:

Код
document.write('<h1>Сумма Вашей покупки : ' + saleTotal + '</h1>');


Промежуточный шаг сохранения результата вызова функции в переменную saleTotal можно и не использовать, а сразу вывести результат вызова функции на страницу:

Код
document.write('<h1>Сумма Вашей покупки : ' + calculateTotal(2500, 5) + '</h1>');


Область видимости функции и предупреждение конфликта переменных.

Чем хороши функции? Они существенно уменьшают объём работы при программировании. Вы можете написать какую-либо функцию для одного проекта и использовать её в других своих проектах.
Но, при этом может возникнуть неприятная ситуация под названием конфликт переменных.

Поясню на примере, создадим какую-то функцию showMessage:

Код
function showMessage(text) {
  document.write(text);
}


ничего особенного: функция с одним параметром, выводящая на страницу значение этого параметра, не акцентируйте на этом внимание.

Внутри функции(внутри фигурных скобок) я создам какую-нибудь переменную number и присвою ей значение 50:

Код
function showMessage(text) {
  document.write(text);
  let number = 50;
}


если сейчас я попытаюсь вывести значение переменной number на страницу, записав команду document.write() после фигурных скобок(вне функции):

Код
function showMessage(text) {
  document.write(text);
  let number = 50;
}

document.write(number);


то получу ошибку в консоли:



это произошло потому, что переменная number "не видна" при обращении к ней извне, вне функции, для сравнения, если ту же команду document.write() мы разместим внутри функции:

Код
function showMessage(text) {
  document.write(text);
  let number = 50;

  document.write(number);
}


то на странице мы увидим значение 50, всё отлично сработает.

Переменная, созданная внутри функции, называется локальной. Локальные переменные не видны вне функции, а только в её пределах.

Теперь рассмотрим ещё один пример: мы объявим нашу переменную number вне функции, а внутри функции попробуем к ней обратиться, чтобы вывести её содержимое на страницу:

Код
let number = 50;
function showMessage(text) {
  document.write(text);
  document.write(number);
}




как видим, всё прекрасно сработало, на страницу вывелось значение 50!

А всё сработало потому, что переменная, объявленная вне функции, называется глобальной, и видна даже изнутри функции, то есть к ней можно обращаться из тела функции.

Закрепим на примере: создаём переменную вне функции, присваиваем ей значение 50, а внутри функции присвоим этой же переменной новое значение, скажем 20.
Затем вне функции с помощью document.write() выведем значение переменной number на страницу. Сработает, изменится первоначальное значение переменной, как вы думаете?

Код
let number = 50;
function showMessage(text) {
  document.write(text);
  number = 20;
}

document.write(number);




Всё прекрасно сработало, первоначальное значение переменной заменилось на новое. Но, помните, в заголовке этой статьи упоминалось о конфликте переменных? Связан он с одинаковыми именами переменных.

Допустим, вы в каком-то своём проекте написали функцию, и в ней использовали переменную с именем number, потом решили, что эта функция может пригодиться в вашем новом проекте и вставили её код в новый проект, но в спешке не обратили внимание, что в новом проекте есть переменная с таким же именем, number.

Тут то и может произойти конфликт переменных. Рассмотрим пример, в котором создадим две переменные с одинаковым именем twin, одну вне функции со строкой "Я вне функции!", другую внутри функции со строкой "Я внутри функции!" :

Код

let twin = 'Я вне функции!';
function showArea() {
  let twin = 'Я внутри функции!';
}


Несмотря на то, что имена этих переменных одинаковые, это две разных переменных! Давайте с помощью document.write() размещённой вне функции, выведем результат на страницу:

Код

let twin = 'Я вне функции!';
function showArea() {
  let twin = 'Я внутри функции!';
}
document.write(twin);




как видим, на страницу вывелось содержимое переменной twin, которая находится вне функции. Если же мы разместим команду document.write() и внутри функции, например так:

Код

let twin = 'Я вне функции!';
function showArea(text) {
  document.write(text);
  let twin = 'Я внутри функции!';
  document.write(twin);
}

showArea('В итоге получаем:<br>');
document.write(twin);


то на страницу выведется также содержимое переменной twin, находящейся внутри функции:



Когда внутри функции есть обращение к какой-либо переменной, функция сначала ищет её внутри себя, а если не находит, то потом уже во внешних переменных, вплоть до высшего уровня.

Например:

Код
let number = 30;
function showMessage() {
  console.log(number);
}


если сейчас вызвать функцию:

Код
showMessage();


то в консоли мы увидим число 30:



более того, если мы вывод переменной в консоль еще дополнительно сделаем вне функции, после её вызова:

Код

let number = 30;
function showMessage() {
  console.log(number);
  }

  showMessage();
  console.log(number);


то в консоли мы увидим дважды число 30, поскольку внутри функции есть обращение к переменной number, но функция её не нашла и пошла выше, где нашла глобальную переменную number и также взяла её значение для вывода в консоль, ну а вторая цифра 30 результат команды console.log вне функции:



Функция вместе со всеми доступными ей внешними переменными образует замыкание.

Ранее мы на примере расчёта стоимости покупки, включая НДС, познакомились с ключевым словом return, с помощью которого можно вернуть результат работы функции, который затем можно либо использовать сразу, либо предварительно сохранить в переменную и затем использовать.

Код

let NDS = 0.18;
function calculateTotal(price,number) {
  let total = price * number * (1 + NDS);
  let totalFormatted = total.toFixed(2);
  return totalFormatted;
}

let saleTotal = calculateTotal(2500, 5);


Ключевое слово return позволяет также вернуть значение переменной, объявленной внутри функции и использовать его вне функции, например:

Код
function returnNum() {
  let number = 50;
  return number;
}

let nextNum = returnNum();


Что тут произошло? В последней строке кода в правой её части производится вызов функции returnNum(),
в результате чего функция запускается, результатом работы функции будет возвращённое значение переменной 50, которое сохранится уже вне функции в переменной nextNum.



Function Declaration и Function Expression

Function Declaration - стандартное объявление функции в потоке кода (как во всех наших примерах выше), при этом функцию можно вызывать как до её объявления, так и после, в обоих случаях код отработает без ошибок.



Function Expression - объявление функции, при котором она присваивается переменной, и по-сути, теперь переменная будет именем функции, по которому к ней можно обратиться для вызова.
В случае Function Expression функция создаётся только в момент выполнения кода, поэтому вызвать заранее её не получится, что можно увидеть на примере ниже.

Код
showMessage('Вызов функции до её объявления');

let showMessage = function(text) {
  console.log(text);
}

showMessage('Вызов функции после её объявления');


в данном примере вызов функции до её объявления не сработает, в консоли мы увидим ошибку:



вызов функции после её объявления отработает как обычно.

Стандарт ES6 и новый синтаксис объявления функций

Если стандартом ES5 предусмотрено объявление функции в виде:

Код
function funcName(a,b) { };


то стандарт ES6 вводит более короткую запись:

Код
let funcName = (a, b) => { };


при этом ключевое слово подразумевается (и не указывается) для функций без тела блока (без кода в фигурных скобках), например:

Код
let funcName = (a, b) => a + b;




Callback-функции (функции обратного вызова)

Callback-функции - это функции, которые выполняются только после завершения другой функции. Callback-функции могут выступать в качестве аргумента другой функции.

Рассмотрим на примере. Создадим функцию first с двумя параметрами one и callback:

Код
function first(one, callback) {

}


в теле функции первой строкой пропишем исполняемый код, использующий параметр one:

Код
function first(one, callback) {
  console.log(one);
}


а второй строкой кода мы запишем вызов функции callback():

Код
function first(one, callback) {
  console.log(one);
  callback();
}


раз мы вызываем функцию callback(), то значит она должна откуда-то взяться? Откуда? Верно, мы передадим её в качестве аргумента в параметр callback функции first!

Вызываем функцию first, первым параметром пусть будет какое-то число, например, 10, а вторым параметром мы как раз запишем функцию, которая запишется в параметр callback:

Код

function first(one, callback) {
  console.log(one);
  callback();
}

first(10, function() {
  console.log('Callback-функция отработала!');
})




Таким образом, функция callback() отработала только после того, как произошел вызов функции first: функция first отработала, в результате чего внутри неё произошел вызов вложенной callback-функции .

В рассмотренном выше примере мы передавали callback-функцию в качестве аргумента при вызове функции first. Но мы можем также задавать callback-функцию и вне вызова функции, а в функцию в качестве аргумента передавать только имя callback-функции.
Смотрим на примере:

Код

function first(one, callback) {
  console.log(one);
  callback();
}

function callFunction() {
  console.log('Callback-функция отработала');
}

first(10, callFunction);




То есть что получилось в итоге: мы создали функцию callFunction, затем вызвали функцию first, у которой в качестве аргументов при её вызове указали число 10 для сохранения в первый параметр one и имя функции callFunction, без скобок, для сохранения во второй параметр callback.

То есть фактически получается вот что:

Код
function first(10, callFunction) {
  console.log(10);
  callFunction();
}

Добавлять комментарии могут только зарегистрированные пользователи.