Функции и ящики
Транскрипт урока
В прошлый раз мы упростили вычисление с помощью констант: мы создали константу для pi, и использовали её для вычисления площади поверхности разных планет. Таким образом мы сократили объём кода, но нам всё ещё требовалось множество повторений:

const surfaceOfMars    = 4 * pi * 3390 * 3390;
const surfaceOfMercury = 4 * pi * 2440 * 2440;
Строка кода называется инструкцией, в JavaScript инструкции должны заканчиваться точкой с запятой. Тут у нас две инструкции и нам нужно повторять всю формулу в каждой из них. Помните — мы не хотим, чтобы в наших программах что-то повторялось.

Было бы здорово, если бы у нас была какая-нибудь специфическая машина, которая вычисляет площадь поверхности любой сферы. Чтобы мы могли делать что-то подобное:

const surfaceOfMars    = surfaceAreaCalculator(3390);
const surfaceOfMercury = surfaceAreaCalculator(2440);
Чтобы можно было просто сказать ей: "эй, surfaceAreaCalculator, скажи мне площадь поверхности сферы с радиусом 3390" и она бы сразу давала ответ.

Отличные новости! Мы можем создавать подобные машины! Их называют функциями, их можно представить в виде чёрных ящиков.
Положите что-нибудь внутрь ящика, и она выплюнет что-то другое. В данном случае ящик surfaceAreaCalculator возьмёт одно число — радиус, а выплюнет другое — площадь поверхности.

В этом примере

const surfaceOfMars = surfaceAreaCalculator(3390);
мы вызываем ящик surfaceAreaCalculator, даём ему 3390 и получаем ответ. Этот ответ затем сохраняется в константе surfaceOfMars.

Важно понимать разницу между определением функции и её вызовом. То, что мы только что сделали, называется вызовом — мы вызвали функцию surfaceAreaCalculator, другими словами, мы предположили, что она уже существует и использовали её.

Но она должна существовать, так что нужно создать её перед тем, как использовать. Нам нужно определить функцию surfaceAreaCalculator. Это определение функции:

(radius) => {
  return 4 * 3.14 * radius * radius;
};
Эта структура со скобками, стрелкой и фигурными скобками определяет функцию. Слово radius в скобках — то, как функция называет число, которое мы передаем в нее. Это параметр функции. Эта конкретная функция принимает один аргумент, но другие функции могут принимать больше аргументов или вообще не принимать аргументов.

Фигурные скобки создают блок. В JavaScript и других языках вы часто сталкиваетесь с блоками. Они создают группу инструкций, таким способом мы понимаем где функция начинается и заканчивается. Эта функция содержит всего одну инструкцию, она начинается с return, а дальше вы видите уже знакомую формулу.

Вы, возможно, уже догадались, что return заставляет ящик выплёвывать результат. Результат вычисления 4 * pi * radius * radius это то, что функция возвращает нам после того, как мы её вызываем.

Теперь нам нужно дать этой функции какое-нибудь название, чтобы по этому названию мы её вызывали. Мне захотелось назвать её surfaceAreaCalculator, но вы можете давать любой функции любое название. Есть определенные правила для названий: например, название не должно содержать пробелы и использовать некоторые специфические слова, как const, но в остальном и функции и константы можно называть почти как захочется.

Мы уже знаем как давать названия численным константам:

const pi = 3.14;
С функциями все точно также:

const surfaceAreaCalculator = (radius) => {
  return 4 * 3.14 * radius * radius;
};
const, название, которое вы хотите, знак равенства и сама функция

Давайте теперь соберём всё вместе:

const surfaceAreaCalculator = (radius) => {
  return 4 * 3.14 * radius * radius;
};

const surfaceOfMars = surfaceAreaCalculator(3390);
В верхней части — определение функции, а затем вызов функции.

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

4 * 3.14 * radius * radius;
4 * 3.14 * 3390 * 3390;
12.56 * 3390 * 3390;
42578.4 * 3390;
144340776;
И функция возвращает число 144340776. Можно представить, что происходит снаружи, когда наша функция возвращает значение:

const surfaceOfMars = surfaceAreaCalculator(3390);
const surfaceOfMars = 144340776;
Теперь surfaceOfMars — это константа с конкретным числовым значением.

Давайте посмотрим на другой пример:

const percentageCalculator = (number, total) => {
  return number * 100 / total;
};
Эта функция принимает два числа и возвращает процент. Если вы дадите ей 40 и 80, она вернёт 50, потому что 40 это 50% от 80.

Как вы видите, когда есть несколько параметров, они разделяются запятыми.

Давайте выведем результат на экран:

console.log("How much of December is gone already? ");
console.log(percentageCalculator(16, 31));
Сегодня 16 декабря, и я хочу узнать, какой процент этого месяца уже прошёл. Посмотрите на код. Вначале мы напечатали строку с вопросом, а потом напечатали то, что возвращает функция percentageCalculator().

Важный момент: вызов функции может быть аргументом для других функций! Как работает функция console.log()? Она принимает аргумент и выводит его на экран. Мы использовали вызов функции percentageCalculator() КАК АРГУМЕНТ и это сработало. Почему? Потому что вначале вызывается наша функция percentageCalculator(), она возвращает результат. Затем с этим результатом как аргументом вызывается функция console.log(). В итоге результат работы percentageCalculator() выводится на экран.

Ок, я свою часть закончил. Теперь ваша очередь писать функции.
Дополнение к уроку
Способы записи функций
Кроме указанного в видео определения функции:

// const <name> = (<argument>) => {
//   return <expressions>;
// };

const identity = (value) => {
  return value;
};
Существует несколько других. Например, если у вас функция-однострочник, то можно использовать сокращенный синтаксис:

// const <name> = (<argument>) => <expressions>;
const identity = (value) => value;
Отличия от полного определения два: пропали фигурные скобки и инструкция return. Сокращенная запись функции делает возврат автоматически. Подразумевается, что внутри такой функции ровно одно выражение, которое вычисляется, и его результат сразу возвращается наружу.

Пример с двумя аргументами:

const sum = (a, b) => a + b;
Так же можно определять функции, используя ключевое слово function:

// Устаревший синтаксис, предпочтительным является () => {}. Кроме синтаксической разницы есть и семантическая.
// Она связана с пока не изученной темой this.
const identity = function(value) {
  return value;
};
или

// Такую функцию можно использовать до её определения (в этом же файле).
function identity(value) {
  return value;
}
Мы изучаем новый стандарт ES7 и используем стрелочные функции. Поэтому в наших курсах мы будем придерживаться такой () => {} формы записи по многим причинам. Во-первых, она лаконичнее, во-вторых, обладает одним важным свойством, которое будет изучено позже, ну а в-третьих, такой способ записи визуально стирает грань между функциями и данными, что очень пригодится нам в будущем.

Некоторые особенности такой формы записи вместо function выходят за рамки базовых курсов, вы о них узнаете в будущем. Если любопытно, то можете почитать статьи по запросу «стрелочные функции es6», например https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/Arrow_functions
или https://habr.com/company/mailru/blog/213455/.
Формальные и фактические параметры функции
Формальными параметрами (или просто параметрами) функции называются имена переменных в определении функции. Например у функции const f = (a, b) => a - b; формальные параметры — это a и b.

Фактические параметры — это то, что было передано в функцию в момент вызова. Например если предыдущую функцию вызвать так f(5, z), где const z = 8, то фактическими параметрами являются 5 и z. Результатом этого вызова будет число -3, а внутри функции на момент конкретного вызова параметр a становится равным 5, а b становится равным 8. Фактические параметры еще называют аргументами функции.

const f = x => x * x;

const y = 5;
console.log(f(y)); // => 25

console.log(f(3)); // => 9
Как видите, нет никакой связи между именами формальных и фактических параметров. Более того, у фактических параметров вообще может не быть имен, как в примере выше, где мы сразу передали число 3 в функцию. Что имеет значение, так это позиция. Во время вызова функции параметры должны передаваться в правильном порядке, и только тогда функция отработает, как предполагается.

const f = (a, b) => a - b;

const x = 5;
const y = 8;

console.log(f(x, y)); // => -3
console.log(f(y, x)); // => 3
Return
Вызов оператора return приводит к изменению течения программы. Последующие инструкции никогда не будут выполнены:

const identity = (value) => {
  return value;
  const a = 3 + 5; // этот код никогда не будет достигнут
};

console.log(identity(10)); // => 10
Выводы
  • Функции подобны специальным машинам, которые мы создаём, чтобы они выполняли что-нибудь для нас.
  • Функции можно представить в виде ящиков, которые принимают что-то и что-то выплёвывают.
  • Функции могут принимать аргументы.
  • И могут возвращать что-то.
Вот пример определения и вызова функции:

const surfaceAreaCalculator = (radius) => {
  return 4 * 3.14 * radius * radius;
};

const surfaceOfMars = surfaceAreaCalculator(3390);
Здесь radius — это параметр функции surfaceAreaCalculator.

Вы можете вызывать функцию и вкладывать вызов другой функции в качестве аргумента:

console.log(surfaceAreaCalculator(3390));
Дополнительные материалы
Тесты
Пройти тест
Может ли программа содержать несколько функций? (доверьтесь своим инстинктам ;)
Верно!
Неверно
Дальше
Проверить
Завершить тест
Могут ли функции возвращать строки (тексты), или они могут возвращать исключительно числа?
Верно!
Неверно
Неверно
Дальше
Проверить
Завершить тест
Дан такой код:

const height = findHeight();

Какое значение будет "записано" в константу height после выполнения?

Верно!
Неверно
Неверно
Дальше
Проверить
Завершить тест
Дан такой код:

const someFunction = (x) => {
  return 10 * 42;
};


const y = someFunction(9281);

Что будет "сохранено" в константе y после выполнения?
Неверно
Верно!
Неверно
Дальше
Проверить
Завершить тест
Каким будет результат вызова функции?

 const firstNum = 10;
 const secondNum = 5;


 const sum = (z, g) => z + g;


 sum(firstNum, secondNum);
Верно!
Неверно! Попробуйте еще раз
Неверно! Попробуйте еще раз
Дальше
Проверить
Завершить тест
Дана такая функция:

const sum = (a, b, c) => {
  return a + b + c;
};

Можно ли в этой ситуации использовать сокращенный синтаксис записи функции?
Неверно
Верно!
Дальше
Проверить
Завершить тест
Пройти еще раз
Пройти еще раз
Пройти еще раз
Пройти еще раз
Упражнение
Реализуйте функцию squareOfSum(), которая принимает на вход два числа и возвращает квадрат суммы этих чисел. Для вычисления значения используйте формулу из курса алгебры: a² + 2 * a * b + b².
Примеры использования

squareOfSum(2, 3) // 25
squareOfSum(1, 10) // 121