Перейти к содержимому
Теория · Первая программа · урок 5 из 7

Порядок вычислений

В прошлом уроке мы написали функцию add и вызывали её по одному разу в строке. Но в одной строке может встретиться сразу несколько знаков действий и вызовов. Тогда важно знать, в каком порядке JavaScript их выполняет.

Вернёмся к кулинарной книге. Шаг «полейте рыбу соусом» нельзя выполнить сразу: повар открывает страницу соуса, готовит его и только потом возвращается к рыбе. Внешний шаг ждёт, пока закончится внутренний.

Давайте посмотрим на программу, где в каждой строке несколько действий:

JavaScript
function add(a, b) {
    return a + b;
}

console.log(1 + 2 * 3); // 7
console.log((1 + 2) * 3); // 9
console.log(10 - 4 - 3); // 3
console.log(add(add(1, 2), 3)); // 6
console.log(add(2 * 3, 1)); // 7

Первые три строки подчиняются правилам знаков действий, а последние две — правилу вызова: сначала вычисляются аргументы, потом сам вызов. Разберём оба правила.

Знаки действий

С числами работают знаки +, - и *. Порядок задают три правила:

  • как в математике, * выполняется раньше + и -;
  • знаки одного уровня, например + и -, выполняются по очереди слева направо;
  • скобки меняют этот порядок.

По этим правилам JavaScript считает первые три строки примера так:

  1. 1 + 2 * 3: сначала 2 * 3, и 1 + 6 даёт 7.
  2. (1 + 2) * 3: скобки заставляют сначала сложить 1 + 2, и 3 * 3 даёт 9.
  3. 10 - 4 - 3: вычитания идут слева направо, поэтому сначала 10 - 4 даёт 6, а затем 6 - 3 даёт 3.

Если сомневаетесь в порядке, поставьте скобки. Скобки вокруг того, что и так выполнилось бы первым, результат не меняют: 1 + (2 * 3) тоже даёт 7.

Вложенные вызовы

Вызов можно передать в другой вызов как аргумент. Такую запись называют вложенным вызовом: сначала выполняется внутренний вызов, и его результат становится аргументом внешнего. Как с соусом: внешний add не начнёт работу, пока внутренний не вернёт готовое число.

Нажмите «Следующий шаг» и следите, как выполнение уходит в add и возвращается с готовым числом. Обратите внимание: внутренний вызов заканчивается раньше внешнего.

ВживуюВызов функции по шагамшаг 1 из 10 · рамок: 1

Строки 1–3 только объявляют add, поэтому выполнение начинается с вызова add(2, 3).

Рамка — место, где живут параметры одного вызова

Последние две строки первого примера выполняются так:

  1. add(1, 2) возвращает 3, затем add(3, 3) возвращает 6.
  2. Аргумент тоже может быть вычислением: сначала вычисляется 2 * 3, то есть 6, и функция получает числа 6 и 1.

У картинки с соусом есть предел. Повар может сварить соус заранее, ещё утром. У JavaScript такого выбора нет: аргументы вычисляются по очереди, слева направо, прямо перед вызовом. Например, в add(add(1, 2), add(3, 4)) сначала add(1, 2) даёт 3, затем add(3, 4) даёт 7, и только потом внешний add(3, 7) возвращает 10.

На собеседовании новичкам часто показывают строку с вызовом внутри вызова и спрашивают, что она напечатает. Найдите самый внутренний вызов и считайте изнутри наружу.

Частая ошибка

Функция должна сложить два числа и удвоить сумму, но скобки забыли:

JavaScript
function doubleSum(a, b) {
    return a + b * 2; // ✗
}

console.log(doubleSum(2, 3)); // 8

Сообщения об ошибке нет, но вместо 10 программа печатает 8: * выполнилось раньше +, и удвоилось только b. Исправление — взять сумму в скобки: return (a + b) * 2;.

Главное

  • * выполняется раньше + и -, знаки одного уровня идут слева направо, а скобки меняют порядок.
  • Сначала вычисляются аргументы, потом выполняется сам вызов.
  • Во вложенном вызове внутренний вызов заканчивается раньше внешнего, и его результат становится аргументом.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом