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

Смотрите, в математике есть концепция абсолютного значения. Оно определяется так:

Не беспокойтесь, это просто: если число положительное, то его абсолютное значение — это то же число; если число отрицательное, то его абсолютное значение — противоположное ему число. Проще говоря, отбросьте знак отрицания, если он есть, и всё.

Это можно представить в виде расстояния от нуля.

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

IF number больше 0 THEN
  return number
IF number меньше 0 THEN
  return -number
IF number равно 0 THEN
  return 0
Это условие и формально оно выглядит вот так:

IF (условие) THEN
  do something
ELSE IF (другое_условие) THEN
  do some other thing
ELSE (none of those conditions) THEN
  do something else
Теперь давайте напишем настоящую функцию:

const abs = (num) => {
  if (num > 0) {
    return num;
  } else if (num < 0) {
    return -num;
  } else {
    return 0;
  }
};
У этой функции один параметр — она принимает извне один аргумент. Затем идёт ключевое слово if, затем условие в скобках, затем — блок инструкций, который запускается, если аргумент отвечает условию. Следующее условие с else if. else if означает, что "если предыдущее условие не было удовлетворено, но это новое удовлетворено — перейти к выполнению следующего блока инструкций".

Таких блоков "else if" может быть несколько, иногда у вас есть множество альтернатив.

Теперь, когда мы разобрались с положительными и отрицательными числами, остался ещё один вариант: что, если у числа значение 0. Заметьте, мы не уточняем, что число явно 0, мы просто указываем else. Это значит "если ни одно из вышеуказанных условий не удовлетворяется, переходить к следующему блоку инструкций." Вы можете спокойно считать, что если число не положительное и не отрицательное, оно может быть только нулём. Но иногда мы совершаем ошибки, думая об условиях и альтернативах, а многие проблемы в программировании появляются из-за ошибочных условий.

Эти условия в скобках могут быть либо true (истина) либо false (ложь). Например, (num > 0) истинно, когда num равно 9 или 15, но ложно, если num имеет значение -18 или, скажем, 0.

Как вы видите математические знаки больше и меньше как бы отвечают ДА или НЕТ, ИСТИНА (true) или ЛОЖЬ (false). Есть другие выражения, которые дают ответы TRUE или FALSE:

===
!==
>
<
>=
<=
Вот несколько примеров

512 === 512; // true
512 === 988; // false

512 !== 378; // true
512 !== 512; // false

512 > 500; // true
512 > 689; // false

512 < 900; // true
512 < -30; // false

512 >= 512; // true
512 >= 777; // false

512 <= 512; // true
512 <= 600; // true
512 <= 5; // false
Область математики, которая изучает значения true и false называется Алгеброй логики. В целом, утверждения любого типа, не только относящиеся к числам, могут быть истинными или ложными. Например, "Я человек" это истина, а "Китай находится в Южной Америке" — ложь.

В JavaScript есть значения true и false, и их можно использовать в условиях. Например, вы можете ввести if true, и это условие всегда будет удовлетворяться, потому что true всегда истинно.

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

AND используется, когда вам нужно, чтобы два условия были истиной. "Я человек AND лошади едят траву" — true, потому что оба утверждения истинны. "Я человек AND свиньи могут летать" — false, потому что одно утверждение истинно, а другое ложно, и вся конструкция в этом случае, объединённая операцией AND — ложна.

Символ для AND — двойной амперсанд &&. Эта так называемая таблица истинности для операции AND — своеобразная шпаргалка:

A	B	A AND B
TRUE	TRUE	TRUE
TRUE	FALSE	FALSE
FALSE	TRUE	FALSE
FALSE	FALSE	FALSE

Так что только TRUE AND TRUE даёт TRUE, а все остальные комбинации содержат FALSE, поэтому их результат — FALSE.

OR используется, если вам нужно, чтобы хотя бы одно условие было true. Тот же пример, "Я человек OR лошади едят траву" — true. "Я человек OR свиньи могут летать" — тоже true. Хотя свиньи и не могут летать, я — человек, поэтому одно из этих двух утверждений — true, что делает всю конструкцию, объединённую OR, true.

Символ для OR — две вертикальных полоски ||.

A	B	A OR B
TRUE	TRUE	TRUE
TRUE	FALSE	TRUE
FALSE	TRUE	TRUE
FALSE	FALSE	FALSE
Если в конструкции присутствует true, значит результат true.
NOT — это просто — это противоположное. NOT true — это false, NOT false — это true. "NOT свиньи могут летать" — true, потому что "свиньи могут летать" — false, а не false — это true.

Символ для NOT — восклицательный знак !.

A	NOT A
TRUE	FALSE
FALSE	TRUE
В программировании обычно есть множество способов выполнения одной операции. Мы можем написать свою функцию абсолютного значения по-другому и получить тот же результат. Давайте попробуем это сделать, используя новые идеи:

const abs = (num) => {
  if (num === 0 || num > 0) {
    return num;
  } else {
    return -num;
  }
};
Теперь у нас есть всего два условия:

  1. Если число имеет значение 0 ИЛИ число больше 0, то возвращать само число.
  2. В любом другом случае возвращать -число.
Можно придумать ещё один способ записи той же функции, например, используя "больше чем или равно". Когда я говорю "та же функция", я имею в виду, что поведение и назначение функции точно такое же, но её внутренности — набор инструкций, из которых она состоит — могут отличаться.
Дополнение к уроку
Условия
Условие формально выглядит так:

if (условие) then
   выполнить что-то
else if (другое_условие) then
   выполнить что-то другое
else (ни одного из тех условий) then
   выполнить что-то ещё
JavaScript-функция, которая принимает значение и возвращает абсолютное значение:

const abs = (num) => {
  if (num > 0) {
    return num;
  } else if (num < 0) {
    return -num;
  } else {
    return 0;
  }
};
Условие может быть либо истинным (true) либо ложным (false). Например, (num > 0) истинно, когда num равно 9 или 15, но ложно, когда num -18 или, скажем, 0.

То, что даёт ответ TRUE или FALSE, называется предикатом.

Математические предикаты в JavaScript:

===
!==
>
<
>=
<=
Примеры:

512 === 512;    // true
512 === 988;    // false

512 !== 378;    // true
512 !== 512;    // false

512 > 500;      // true
512 > 689;      // false

512 < 900;      // true
512 < -30;      // false

512 >= 512;     // true
512 >= 777;     // false

512 <= 512;     // true
512 <= 600;     // true
512 <= 5;       // false
AND(&&):

| A     | B     | A AND B |
| ----- | ----- | ------- |
| TRUE  | TRUE  | TRUE    |
| TRUE  | FALSE | FALSE   |
| FALSE | TRUE  | FALSE   |
| FALSE | FALSE | FALSE   |
OR (||):

| A     | B     | A OR B |
| ----- | ----- | ------ |
| TRUE  | TRUE  | TRUE   |
| TRUE  | FALSE | TRUE   |
| FALSE | TRUE  | TRUE   |
| FALSE | FALSE | FALSE  |
NOT (!):

| A     | NOT A |
| ----- | ----- |
| TRUE  | FALSE |
| FALSE | TRUE  |
Альтернативный способ реализации функции abs:

const abs = (num) => {
  if (num === 0 || num > 0) {
    return num;
  } else {
    return -num;
  }
};
Можно придумать другой способ реализации той же функции, с использованием символа >= .

Та же функция значит: "назначение функции то же, но внутренность (реализация) может отличаться".
Тернарный оператор
В JavaScript и многих других языках есть сокращённая версия if: она называется тернарным оператором (ternary operator):

condition ? expression : expression
В этом случае есть только одно составное условие и два варианта: один для true и один для false.

const absValue = (num === 0 || num > 0) ? num : -num;
Мы создаём absValue и присваиваем ему значение. Это значение зависит от условия: если условие истинно, тогда используется num, в противном случае используется -num.
Тернарная операция VS условная конструкция if
Между этими двумя элементами языка есть различия. Тернарная, или условная, операция вычисляет и возвращает значение, то есть является выражением. Это значит, что мы можем сохранить результат вычисления этого выражения в константе, например:

const absValue = (num >= 0) ? num : -num;
Условная конструкция if в JavaScript выражением НЕ является. Это инструкция — она выполняет действие, ничего не вычисляя и не возвращая. Как следствие, мы НЕ можем с помощью конструкции if сделать так же:

const absValue = if (num >= 0) { ... }; // unknown: Unexpected token
Такая строчка кода приведёт к ошибке. Кстати, в некоторых других языках, например в Ruby, if реализован как выражение, поэтому там подобное присваивание возможно.

Чтобы сделать то же самое, придётся "попотеть":

let absValue;

if (num >= 0) {
  absValue = num;
} else {
  absValue = -num;
}
Как видно, код стал более громоздким и сложным. Более того, нам пришлось ввести изменяемое состояние — вместо константы const использовать переменную (let). То есть мы позволили всему остальному коду изменять значение absValue, хотя объективно это больше нигде не понадобится. Тем самым мы заложили потенциальную возможность для будущих ошибок.

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

const getAbs = num => (num >= 0) ? num : -num;
Вместо унылого:

const getAbs = (num) => {
  if (num >= 0) {
    return num;
  }
  return -num;
};
Таким образом, тернарная операция позволяет писать более лаконичный и простой код. Но не стоит увлекаться, у неё есть свои минусы и ограничения по сравнению с конструкцией if, всё зависит от конкретной ситуации:
  • "Вложенные" тернарные операции выглядят эффектно, но ухудшают читабельность кода:

const type = (num > 0) ? 'positive' : (num < 0) ? 'negative' : 'zero';
  • Тернарная операция не подойдёт, если в зависимости от условия надо выполнить несколько (а не одно выражение) строчек кода (блок кода). Нужна условная конструкция if:

if (condition) {
  statement;
  ... ;
  ... ;
} else {
  statement;
  ...;
  ...;
}
  • Используя в теле функции, мы можем легко вернуть результат вычисления тернарника, поставив его после инструкции return. Ведь это обыкновенное выражение. Однако, инструкцию return нельзя использовать внутри тернарной операции. Интерпретатор вас не поймёт и выкинет ошибку:

const getAbs = (num) => {
  (num >= 0) ? return num : return -num;
};

const result = getAbs(-3); // unknown: Unexpected token
Дополнительные материалы
Тесты
Пройти тест
Каким будет результат (12 > 40) || (400 >= 400)?

Неверно!
Верно!
Неверно
Дальше
Проверить
Завершить тест
if (a > 100) {
  something;
} else if (a === 95) {
  something_different;
} else if (a === 90) {
  something_different_yet;
} else {
  something_else;
}

Что будет, если ни одно условие из блоков if и else if не будет истинным?
Неверно
Верно!
Неверно
Дальше
Проверить
Завершить тест
Я смотрю на логический оператор. В нем два выражения и операция между ними. Одно из выражений истинно (true), второе выражение неизвестно, и результат операции — истина. Какой может быть операция?

(нужно выбрать все корректные ответы)
Верно!
Верно!
Неверно
Дальше
Проверить
Завершить тест
Дан код:

if (temperature > 10) {
  return temperature;
}
else if (temperature < 10) {
  return 0;
}

Изменится ли функциональность, если поменять местами условия таким образом:

if (temperature < 10) {
  return 0;
} else if (temperature > 10) {
  return temperature;
}
Верно!
Неверно
Дальше
Проверить
Завершить тест
Дан код:

if (temperature > 10) {
  return temperature;
}
else if (temperature < 10) {
  return 0;
}

Изменится ли функциональность, если изменить else if на else?
Верно!
Неверно
Дальше
Проверить
Завершить тест
Можно ли использовать if для проверки одного условия, без else if и без else?
Неверно
Неверно
Верно!
Неверно
Дальше
Проверить
Завершить тест
Проанализируйте следующий код (см. «Тернарный оператор» в тексте урока):

// функция-предикат определяет, является ли число num четным
const isEven = num => num % 2 === 0;


// функция увеличивает полученное число num на 10
const increaseNum = num => num + 10;


const num = 6;


const result = isEven(increaseNum(num) + 1) ? num + 1 : 1 - num;

Какое значение содержит константа result?
Неверно
Верно!
Неверно
Неверно
Неверно
Дальше
Проверить
Завершить тест
Этот скрипт определяет оценку в зависимости от набранных в тесте баллов:

 const testScore = 10;
 const result = testScore < 10 ? 'bad' : 'good';
 console.log(result);

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

Функция принимает два аргумента:

  • exam — оценка за экзамен, число от 0 до 100;
  • projects — количество проектов, число от 0 и выше.
Функция возвращает: число (итоговую оценку).

Есть четыре возможных итоговых оценки:

  • 100, если оценка за экзамен выше 90 или есть больше 10 проектов
  • 90, если оценка за экзамен выше 75 и есть как минимум 5 проектов
  • 75, если оценка за экзамен выше 50 и есть как минимум 2 проекта
  • 0 в любом другом случае
Вот как должна работать ваша функция:

пример вызова         // что должна вернуть функция при таком вызове
finalGrade(100, 12);  // 100
finalGrade(99, 0);    // 100
finalGrade(10, 15);   // 100
 
finalGrade(85, 5);    // 90
 
finalGrade(55, 3);    // 75
 
finalGrade(55, 0);    // 0
finalGrade(20, 2);    // 0