Практикум №2

Описание задания вы всегда можете посмотреть под спойлером.



В предыдущем уроке мы остановились на следующем финальном коде:

Код

let money = +prompt('Ваш бюджет на месяц?', '');
let time = prompt('Введите дату в формате YYYY-MM-DD', '');

let appData = {
  budget: money,
  timeData: time,
  expenses: {},
  optionalExpenses: {},
  income: [],
  savings: false
}

let answer1 = prompt('Введите обязательную статью расходов в этом месяце', ''),
  answer2 = prompt('Во сколько обойдется?', ''),
  answer3 = prompt('Введите обязательную статью расходов в этом месяце', ''),
  answer4 = prompt('Во сколько обойдется?', '');

appData.expenses.answer1 = answer2;
appData.expenses.answer3 = answer4;

alert(appData.budget / 30);


Давайте с помощью цикла while предотвратим возможный неправильный ответ пользователя на вопрос "Ваш бюджет на месяц?"
Ведь пользователь не обязательно в ответе укажет числовое значение, он может ответить, к примеру, "Сто тысяч" вместо 100 000, а это не то, что нам нужно, верно?

Напомню, основная конструкция цикла while такова:

Код

while (условие) {
  здесь повторяющийся код, который выполняется, пока условие истинно
}


применительно к нашей задаче цикл будет выглядеть так:

Код

while( isNaN(money) || money == null || money == '' ) {
  money = +prompt('Введите ваш бюджет на месяц', '');
}


первое условие в блоке:

Код
isNaN(money)


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

Код
money == null


проверяет, не оставил ли пользователь поле ввода пустым, нажав кнопку "Отмена", а третье условие:

Код
money == ''


проверяет, не оставил ли пользователь поле ввода пустым, нажав кнопку "Ок".

Вот и всё, теперь, пока пользователь не введёт корректные данные (а именно: числовое значение) на вопрос "Ваш бюджет на месяц?", ему бесконечно будет предлагаться это сделать.

Как вы помните, одним из пунктов задания было " Задать (по 2 раза) следующие вопросы пользователю:

- "Введите обязательную статью расходов в этом месяце"
- "Во сколько обойдется?"

И мы реализовали это через объявление четырёх разных переменных, каждая из которых в качестве значения имела диалог prompt() с вопросом.

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

- "Введите обязательную статью расходов в этом месяце"
- "Во сколько обойдется?"

Следуя такому пути, к примеру, если бы нам понадобилось задать каждый вопрос по 3 раза, то нам пришлось бы уже создавать целых шесть(!) переменных.

Гораздо правильнее повторяющиеся операции реализовать с помощью цикла. Мы реализуем нашу задачу с задаванием вопросов с помощью цикла for.
Найдите в коде нашего скрипта этот участок кода:

Код

let answer1 = prompt('Введите обязательную статью расходов в этом месяце', ''),
  answer2 = prompt('Во сколько обойдется?', ''),
  answer3 = prompt('Введите обязательную статью расходов в этом месяце', ''),
  answer4 = prompt('Во сколько обойдется?', '');


вместо него мы напишем наш цикл:

Код

for( let i = 0; i < 2; i++) {
  let a = prompt('Введите обязательную статью расходов в этом месяце', ''),
  b = prompt('Во сколько обойдётся?', '');
}


В условии цикла внутри круглых скобок мы объявили переменную i с начальным значением 0, это наш счётчик, с которого начнёт работу цикл.

Далее, мы прописали условие, при котором цикл прекратит работу (в противном случае, если этого условия не будет, цикл станет бесконечным), и наше условие таково, что i < 2, поскольку вопроса у нас 2.

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

Итак, i = 0, так как 0 меньше 2, это истина, поэтому выполняется код в фигурных скобках и пользователь увидит последовательно два модальных окна с вопросами 'Введите обязательную статью расходов в этом месяце' и 'Во сколько обойдётся?'
После того, как этот первый проход цикла закончится, в переменной i будет уже 0 + 1 = 1.

i = 1, 1 < 2, это по-прежнему истина, поэтому, как и в предыдущем шаге, всё повторяется, а в конце итерации значение i будет уже 1 + 1 = 2. И на этом цикл завершит свою работу, потому как 2 < 2 это ложь.

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

Теперь найдите в нашем файле скрипта вот этот участок кода:

Код

appData.expenses.answer1 = answer2;
appData.expenses.answer3 = answer4;


нам нужно его удалить, поскольку у нас уже нет больше этих переменных, а вместо этого в цикле в фигурных скобках мы запишем добавление свойства в объект таким образом:

Код

appData.expenses[a] = b;


то есть полностью наш цикл сейчас должен выглядеть так:

Код

for( let i = 0; i < 2; i++) {
  let a = prompt('Введите обязательную статью расходов в этом месяце', ''),
  b = prompt('Во сколько обойдётся?', '');

  appData.expenses[a] = b;  
}


Если сейчас мы откроем наш файл index.html в браузере, скрипт начнёт работу, появится сначала одно диалоговое окно, потом другое, и если мы корректно ответим на все вопросы, то результат работы скрипта можно увидеть в консоли браузера.

Попробовать скрипт в работе

Как посмотреть конечный результат работы скрипта? После того, как вы ответите на все вопросы в модальных окнах, откройте консоль браузера (я работаю в браузере Opera и здесь консоль открывается комбинацией клавиш Ctrl + Shift + I) и в консоли наберите команду:

Код
console.log(appData);


вот, к примеру, скриншот того, что я получил у себя, отвечая на вопросы в модальных окнах:



Как видим, скрипт отработал нормально, все ответы, вводимые мной в модальных окнах, в конечном счёте попали в наш объект appData.

А как вам такой вариант? Пользователь решил вовсе не отвечать на вопрос и нажал кнопку "Отмена", либо не заполнив поле для ответа, решил, что и так сойдёт и нажал кнопку "Ок"?

Попробуйте, посмотрите, что получится в итоге, если вы решите проигнорировать ответы на вопросы, либо ввести вместо числа что-то иное:

Посмотреть, что получится

А получится не совсем весёлая картина, а самое грустное, что всё это безобразие отработает, и никакой ошибки не выдаст (ну разве что в конце работы скрипта выдаст вам баNaN).

Хороший программист должен предвидеть различные варианты событий, как тот шахматист, что видит игру на много ходов вперёд.
Поэтому нам нужно также предусмотреть варианты, когда пользователь некорректно отвечает на вопросы в модальных окнах, либо вовсе не отвечает на них.

Итак, будем дорабатывать наш цикл с учётом вышесказанного. Сейчас он имеет такой вид:

Код

for( let i = 0; i < 2; i++) {
  let a = prompt('Введите обязательную статью расходов в этом месяце', ''),
  b = prompt('Во сколько обойдётся?', '');

  appData.expenses[a] = b;  
}


После объявления переменных a и b в фигурных скобках начинаем писать наши условия:

Код

for( let i = 0; i < 2; i++) {
  let a = prompt('Введите обязательную статью расходов в этом месяце', ''),
  b = prompt('Во сколько обойдётся?', '');

  if( typeof(a) != null && typeof(b) != null && a != '' && b != '' && a.length < 50) {
   
  appData.expenses[a] = b;  
  }
   
}


первые два условия

Код
typeof(a) != null && typeof(b) != null


null получается как раз в том случае, если пользователь при возникновении диалогового окна нажимает кнопку "Отмена", поэтому два первых условия это и проверяют.

Вторые два условия

Код
a != '' && b != ''


проверяют, не являются ли значения переменных a и b пустой строкой (тот случай, если пользователь ничего не заполнил и нажал кнопку "Ок")

и последнее условие:

Код
a.length < 50


проверяет, не ввёл ли пользователь больше 50 символов в поле.

Ну а строку

Код
appData.expenses[a] = b;


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

И конечно, нам нужно прописать альтернативный вариант развития событий (если какое-то условие не оказалось истинным), делаем это с помощью else:

Код

for( let i = 0; i < 2; i++) {
  let a = prompt('Введите обязательную статью расходов в этом месяце', ''),
  b = prompt('Во сколько обойдётся?', '');

  if( typeof(a) != null && typeof(b) != null && a != '' && b != '' && a.length < 50) {
   
  appData.expenses[a] = b;  
  } else {
  i--;
  }
   
}


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

Код
if( typeof(a) != null && typeof(b) != null && a != '' && b != '' && a.length < 50)


не будут выполнены, вопросы так и будут задаваться, поскольку за счёт именно i-- условие вот тут:

Код
for( let i = 0; i < 2; i++)


будет всегда истина (потому что i++ из условия цикла и i-- из альтернативного варианта управляющей инструкции if/else будут в итоге давать нулевой результат и потому значение переменной i будет оставаться неизменным i = 0), а значит цикл будет повторяться снова и снова.

Добавим теперь в наш объект appData новое свойство, отражающее дневной бюджет пользователя, назовём его moneyPerDay:

Код
appData.moneyPerDay = appData.budget / 30;


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

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

Код

if(appData.moneyPerDay < 500) {
  console.log('Низкий уровень дохода');
} else if(appData.moneyPerDay > 500 && appData.moneyPerDay < 1000) {
  console.log('Средний уровень дохода');
} else if(appData.moneyPerDay > 1000) {
  console.log('Высокий уровень дохода');
} else {
  console.log('Что-то пошло не так');
}


Полностью законченный код скрипта этого урока:

Код

let money = +prompt('Ваш бюджет на месяц?', '');
let time = prompt('Введите дату в формате YYYY-MM-DD', '');

while( isNaN(money) || money == null || money == '' ) {
  money = +prompt('Введите ваш бюджет на месяц', '');
}

let appData = {
  budget: money,
  timeData: time,
  expenses: {},
  optionalExpenses: {},
  income: [],
  savings: false
}

for( let i = 0; i < 2; i++) {
  let a = prompt('Введите обязательную статью расходов в этом месяце', ''),
  b = prompt('Во сколько обойдётся?', '');

  if( typeof(a) != null && typeof(b) != null && a != '' && b != '' && a.length < 50) {
   
  appData.expenses[a] = b;  
  } else {
  i--;
  }
   
}

appData.moneyPerDay = appData.budget / 30;
alert(appData.budget / 30);

if(appData.moneyPerDay < 500) {
  console.log('Низкий уровень дохода');
} else if(appData.moneyPerDay > 500 && appData.moneyPerDay < 1000) {
  console.log('Средний уровень дохода');
} else if(appData.moneyPerDay > 1000) {
  console.log('Высокий уровень дохода');
} else {
  console.log('Что-то пошло не так');
}


Протестировать работу скрипта

Комментарии к материалу: