5 / Дополнительные возможности

Мы уже научились создавать массивы, в том числе с разными типами данных, и обращаться к элементам по индексу. Например:
let student = ["Иван", 20, "м"];
student[0] = "Максим";
А можно ли вместо индекса использовать строки, чтобы обращаться к разным элементам массива по именам? Например:
student["name"] = "Максим";
Да, в JS есть механизм, позволяющий так делать:
function info() {
let student = {
name: "Иван",
age: 20,
gender: "м"
};
return student;
}
Вызови функцию: info()

Результат: {name: "Иван", age: 20, gender: "м"}

В начале функции мы создали переменную student и присвоили ей объект (структуру данных). Объект задаётся с помощью фигурных скобок.

Внутри скобок через запятую мы указали элементы объекта, которые называются свойствами. Иногда их ещё называют полями.

Через двоеточие указываются значения свойств.

В нашем примере в переменной student будет хранится объект со следующими свойствами:

Свойства объекта student

Получить свойство объекта можно с помощью квадратных скобок. Например, student["name"]:
function info() {
let student = {
name: "Иван",
age: 20,
gender: "м"
};
return student["name"];
}
Вызови функцию: info()

Результат: "Иван"

Также получить свойство объекта можно через точку. Например, student.name:
function info() {
let student = {
name: "Иван",
age: 20,
gender: "м"
};
return student.name;
}
Свойство объекта может содержать пробел, но тогда его необходимо указывать в кавычках:
function info() {
let student = {
name: "Иван",
age: 20,
gender: "м",
"Семейное положение": "холост"
};
return student;
}
В этом случае обращаться к свойству объекта можно только через квадратные скобки, иначе будет ошибка.

  • С помощью точки или квадратных скобок можно менять значения свойств.
  • Если свойство отсутствовало в объекте, оно будет добавлено.
function info() {
let student = {
name: "Иван",
age: 20,
gender: "м"
};
student.name = "Максим";
student["Семейное положение"] = "холост";
return student;
}
Вызови функцию: info()

Результат: {name: "Максим", age: 20, gender: "м", Семейное положение: "холост"}

Свойство name было изменено на "Максим". Свойство "Семейное положение" было добавлено со значением "холост".
Упражнения
5.1.1. Напиши функцию, которая принимает три параметра: имя, возраст и пол, и преобразовывает эти параметры в объект со свойствами name, age, gender.
5.1.2. Напиши функцию, которая принимает два параметра: объект с информацией о студенте и отметку за экзамен. Функция должна добавлять свойство mark (отметка) в объект и возвращать его.
5.1.3. Напиши функцию, которая принимает один параметр: объект с информацией о студенте. Если свойство mark (отметка за экзамен) равно 5, функция должна вернуть строку отлично. Если свойство mark равно 4, функция должна вернуть строку хорошо. Если свойство mark равно 3, функция должна вернуть строку удовлетворительно. Если свойство mark меньше 3, функция должна вернуть строку неудовлетворительно. Иначе функция должна вернуть строку оценка неизвестна.

Функции

Мы уже знаем, что такое функции, как их объявлять, вызывать и как передавать в них параметры.

Параметры функции также называют аргументами. Например, функция принимает два аргумента — значит, функция принимает два параметра.

Давай рассмотрим ещё некоторые особенности работы с функциями.

Функции могут возвращать результат вычислений, а могут не возвращать. То есть слово return в функции можно не использовать.

Такие функции обычно используются для изменения значения глобальной переменной.

Глобальная переменная — это переменная, которую можно использовать в любой части кода.

Например, создай переменную:
let hello = "Привет!";
Затем создай функцию, которая будет изменять значение этой переменной:
function change() {
hello = "Мир!"
}
Проверим значение переменной. Для этого можно просто написать в консоли hello.

Значение равно "Привет!".

Теперь вызовем функцию change(). Браузер вернёт undefined, что доказывает, что функция ничего не вернула.

Проверим ещё раз значение переменной hello.

Теперь значение равно "Мир!". Оно изменилось в функции change, когда мы её вызвали.

Мы можем сохранить значение, которое было вычислено в функции, в переменную в одной строке. Для начала возьмём функцию ниже.
function add(a, b) {
return a + b;
}
А потом сохраним результат функции в переменную:
let sum = add(8, 2);
Проверим значение переменной, просто написав в консоли sum.

Результат: 10.

Теперь мы можем использовать sum в дальнейших вычислениях:
sum * 2
В консоль выведется: 20.

И, конечно, одни функции можно вызывать из других функций.
function add(a, b) {
return a + b;
}

function sub(a, b) {
return a - b;
}

function calc(a, operation, b) {
if (operation == "+") {
return add(a, b);
} else if (operation == "-") {
return sub(a, b);
}
return"Ошибка: неизвестная операция.";
}
Вызови функцию calc(8, "+", 2)

Результат: 10

Теперь вызови calc(8, "-", 2)

Результат: 6

Итак, мы создали сразу 3 функции:
  • add(a, b) — считает сумму a + b
  • sub(a, b) — считает разность a - b
  • calc(a, operation, b) — проверяет значение аргумента operation:
Если operation == "+", вызывает add(a, b) и сразу возвращает результат сложения.
Если operation == "-", вызывает sub(a, b) и сразу возвращает результат вычитания. В противном случае возвращает ошибку.
Упражнения
5.2.1. Напиши 3 функции, каждая из которых возвращает одну строку:
  • Красный свет. Стой
  • Жёлтый свет. Внимание
  • Зелёный свет. Иди
Напиши функцию lights, которая принимает один параметр color (цвет). В зависимости от значения red, yellow, green эта функция должна вызывать одну из тех трёх и возвращать результат. Или же возвращать ошибку.
5.2.2. Напиши 4 функции, принимающие по 2 параметра и выполняющие математические операции:
  • add (сложение),
  • sub (вычитание),
  • mul (умножение),
  • div (деление).
Напиши функцию calc, принимающую 3 параметра: aoperationb. В зависимости от значения operation эта функция должна вызывать одну из тех четырёх и возвращать результат. Или же возвращать ошибку.

Логические операторы

Мы уже умеем в JS работать с целыми числами, десятичными, со строками и массивами.

Ещё одним важным типом данных является логический. Его называют булевым типом — в честь одного из основателей математической логики Джорджа Буля.

Значения для такого типа данных — только истина (true) или ложь (false). Это как с лампочкой, ВКЛ или ВЫКЛ. Другими словами, когда лампочка включена — это истина, когда выключена — это ложь.

Значения true и false можно сохранять в переменные и возвращать из функции:
function isRain() {
let rain = true;
return rain;
}
Вызови isRain()

Результат: true

Логические переменные мы можем использовать в условиях:
function needUmbrella(rain) {
if (rain) { // Ты уже видел эту задачу, мы проговорили бытовым языком,
return "Идёт дождь. Надо взять зонтик."; // что если идёт дождь, то необходимо взять зонт.
} // Теперь давай добавим теории к этой истории
return "Хорошая погода."; // Условие выполняется — это булева логика, правда или ложь.
} // Ты будешь постоянно работать с этой концепцией на практике.
Вызови needUmbrella(true)

Результат: "Идёт дождь. Надо взять зонтик."

Вызови needUmbrella(false)

Результат: "Хорошая погода."

У логической переменной можно получить обратное значение. Эта операция эквивалентна отрицанию НЕ:

  • не истина = ложь
  • не ложь = истина

Таблица истинности операции НЕ

В JS логическое НЕ обозначается с помощью оператора ! перед переменной:
function isGoodWeather(rain) {
let goodWeather = !rain;
return goodWeather;
}
Вызови goodWeather(true)

Результат: false.

Вызови goodWeather(false)

Результат: true.
function needSunglasses(rain) {
if (!rain) {
return "Дождя нет. Надо взять солнцезащитные очки.";
}
return "Идёт дождь.";
}
Вызови needSunglasses(true)

Результат: "Идёт дождь."

Вызови needSunglasses(false)

Результат: "Дождя нет. Надо взять солнцезащитные очки."

Часто используемой операцией с логическими данными является логическое И.

Логическое И возвращает истину, если оба логических выражения истинны. По смыслу ближе всего к союзу "и".

Например, чтобы была радуга, надо, чтобы одновременно были дождь и солнце. Если не будет дождя или не будет солнца, или ни дождя, ни солнца, то не будет и радуги.

Таблица истинности операции И

В JS логическое И обозначается с помощью оператора &&:
function isRainbow(rain, sun) {
return rain && sun;
}
Вызови isRainbow(true, true)

Результат: true.

Вызови isRainbow(true, false)

Результат: false.

Ещё одной часто используемой операцией с логическими данными является логическое ИЛИ.

Логическое ИЛИ возвращает истину, если хотя бы одно логическое выражение истинно.

По смыслу ближе всего к союзу "или" в значении "или одно, или другое, или оба сразу".

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

Таблица истинности операции ИЛИ

В JS логическое ИЛИ обозначается с помощью оператора ||:
function isPrecipitation(rain, snow) {
return rain || snow;
}
Вызови isPrecipitation(true, true)

Результат: true

Вызови isPrecipitation(true, false)

Результат: true
Упражнения
5.3.1. Напиши функцию, которая принимает два параметра: логин и пароль. Если логин равен admin и пароль равен 12345, функция возвращает строку Вход выполнен. Иначе функция возвращает строку Неверный логин или пароль.
5.3.2. Напиши функцию, которая проверяет, находятся ли три числа по порядку. Функция должна принимать три числа. Если первое число меньше второго и второе меньше третьего, функция выводит строку Числа в порядке возрастания. Если первое число больше второго и второе больше третьего, функция выводит строку Числа в порядке убывания. Иначе функция выводит строку Числа не упорядочены.
5.3.3. Напиши функцию, которая принимает возраст и пол (мж). Если возраст меньше 12, возвращает строку ребёнок. Если возраст меньше 18, возвращает строку подросток. Если м и возраст меньше 30, возвращает строку молодой человек. Если ж и возраст меньше 30, возвращает строку девушка. Если м и возраст меньше 60, возвращает строку мужчина. Если ж и возраст меньше 60, возвращает строку женщина. Иначе для м возвращает строку дедушка, для ж — строку бабушка.
Бонус
Рассмотрим небольшой пример:
function test(a) {
if (a == 1) {
return "true";
}
return "false";
}
Всё просто — функция, которая принимает один параметр. Если это 1, возвращает true. В противном случае возвращает false.

Попробуй вызвать test(1) и test(2).

В первом случае вернётся true, во втором false. Всё просто.

А теперь представим, что ты допустил ошибку:
function test(a) {
if (a = 1) {
return "true";
}
return "false";
}
В условии вместо == случайно поставил присвоение =.

Попробуй теперь вызвать test(1) и test(2).

В обоих случаях вернётся true. Почему так?

Дело в том, что в этом случае в переменную a записывается значение 1 и условие проверяет, является ли истинным значение a. Грубо говоря, запись if (a = 1) раскладывается на две команды:
a = 1;
if (a) { ... }
Так как значение a равно 1, JS считает, что условие истинно и переходит внутрь тела.

Спутать двойное == и одинарное довольно просто, а обнаружить ошибку сложно, особенно когда код состоит из нескольких тысяч строк.

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

Один из них ты можешь усвоить уже сейчас. Для этого просто при сравнении перед =пиши неизменяемую часть условия, а после == изменяемую:
if (1 == a) { ... }
С точки зрения JS записи if (a == 1) и if (1 == a) эквивалентны, ошибки не будет. А записи if (a = 1) и if (1 = a) не эквивалентны, так как единице нельзя присвоить значение переменной a. JS выдаст ошибку, что сэкономит тебе много времени и нервов на поиски.

Итак, код примера теперь будет выглядеть вот так, и написать одно = вместо == уже не получится:
function test(a) {
if (1 == a) {
return "true";
}
return "false";
}
P.S. Использование данного лайфхака может положительно сказаться на собеседовании: работодатель увидит, что кандидат задумывается о таких проблемах, и старается сделать свой код надёжнее.