Как написать калькулятор на javascript тестовое задание jm

Тестовое задание Frontend

Вам потребуется решить кодовую задачу на языке JavaScript.

Ссылка на задачу: https://repl.it/@JavaMentor/RomanCalculator

После решения задачи, сохраняем ссылку на решение (скопировать url).

Решение сохраняется на платформе под уникальным url, которое нужно будет выслать нам на почту info@java-mentor.com с темой «Тестовое задание Front-end»

Задача Calculator

Описание

Создайте функцию calculate.
Функция должна принимать арифметические операции двух чисел в виде строки и возвращать строку с результатом их выполнения.
Функция принимает данные из аргументов и возвращает с помощью return.

Требования

  • Решение должно пройти все тесты.
  • Калькулятор умеет выполнять операции сложения, вычитания, умножения и деления с двумя числами: a + b, a — b, a * b, a / b. Данные передаются в виде одной строки!
  • Калькулятор умеет работать как с арабскими (1,2,3,4,5…), так и с римскими (I,II,III,IV,V…) числами. Оба операнда должны быть либо арабскими, либо римскими.
  • Операнды должны лежать в диапазоне от 1 до 10 включительно, без ноля. Ответ может быть больше 10.
  • Калькулятор умеет работать только с целыми числами, принимает и возвращает.
  • Результат на выходе всегда строка с целым числом. В делении учитываем только целую часть — десятичную отбрасываем, например 2 / 4 = 0,5 — вернём 0.
  • Калькулятор умеет работать только с арабскими или римскими цифрами одновременно, при вводе пользователем строки вроде 3 + II калькулятор должен выбросить исключение (ошибку) и прекратить свою работу.
  • Поскольку в римской системе счисления нет нуля и отрицательных чисел, то вместо них возвращаем пустую строку. (например I — II = »)
  • При вызове калькулятора с неподходящими числами, функция выбрасывает исключение и завершает свою работу.
  • При вызове калькулятора со строкой, которая не является математическим примером с одной из арифметических операций, описанных в требовании, приложение выбрасывает исключение и завершает свою работу.

Пример работы программы

calculate('1 + 2'); // вернется строка '3'
calculate('VI / III'); // вернется строка 'II'
calculate('VII / III'); // вернётся строка II'
calculate('I + II'); // вернется строка 'III'
calculate('I - II'); // вернётся строка '' (пустая строка) т.к. в римской системе нет отрицательных чисел
calculate('I + 1'); // вернётся исключение (ошибка) throws Error т.к. используются одновременно разные системы счисления
calculate('I'); // вернётся исключение throws Error т.к. строка не является математической операцией
calculate('1 + 1 + 1'); // вернётся исключение throws Error т.к. формат математической операции не удовлетворяет заданию - два операнда и один оператор (+, -, /, *)

Работа с repl.it

  1. Необходимо зарегистироваться или залогиниться на платформе https://replit.com/
  2. Перейти по сслыке https://repl.it/@JavaMentor/RomanCalculator и нажать кнопку «Fork», чтобы начать решать задачу

Основной интерфейс:

Интерфейс

После нажатия кнопки “run” ваш код будет протестирован. Результаты тестов будет выведен в консоль. В консоли может быть как сообщение об успешном выполнении, так и сообщения об ошибках.
Вам нужно написать такой код, который пройдет все проверки.

Решение не прошло проверку

Успешное решение задачи:

Требования

  • Ты должен решить задачу самостоятельно, без чьей-либо помощи.
  • Можно пользоваться гуглом, но не ищи готовое решение задачи.

Как отправить решение?

Ссылки на решение отправьте нам на почту info@java-mentor.com с темой «Тестовое задание Front-end»

FAQ

С чего начать?

Ознакомься со списком тем, изучение которых поможет с задачей:

  • Типы данных
  • Переменные
  • Методы массива и объекта
  • Преобразование типов данных (из строки в число и обратно)
  • Операция с числами (округление, деление и тд)
  • Обработка ошибок, проброс исключений
  • Типа ошибок в JS и что означают
  • Функции
  • Циклы, сравнение, условные конструкции if-else и switch-case
  • Логические операторы

Начни свой путь к решению задачи с изучения ресурсов, которые помогут в подготовке:

ВНИМАНИЕ! Не нужно смотреть все видео из плейлиста, также не нужно проходить курсы от начала и до конца. У тебя 7 дней на решение задачи, поэтому не трать время. Сверься со списком тем выше и посмотри выборочно материалы только по этим темам! Для того, чтобы сэкономить твое время, выбери один-два источника из предложенных и используй их для решения ТЗ. Помни, твоя цель — решить задачу, а не изучить JS полностью самостоятельно.

  • https://www.youtube.com/watch?v=T3IgBNN9bhM&list=PLVfMKQXDAhGUaEtJ_fOUz0F7TJtidE7Qw — канал на Youtube Web Developer Blog, плейлист с видео для начинающих
  • https://ru.code-basics.com/languages/javascript — интерактивный курс по основам. Полное прохождение курса займет неделю, лучше совместить с параллельным изучением других источников, для решения ТЗ одного этого курса будет мало.
  • https://ru.hexlet.io/courses/introduction_to_programming — более углубленный интерактив
  • https://learn.javascript.ru/first-steps / https://learn.javascript.ru/data-types / https://learn.javascript.ru/error-handling — основы языка в виде коротких статей

Программа JavaScript

Я знаю другой язык программирования, но не знаю JavaScript.

  1. Side-by-side code snippets — сравнение примеров кодов на разных языках. Выбираем ваш язык и javascript — изучаем сходства/различия.
  2. Learn X in Y minutes — JS — Короткий обзор синтаксиса языка.
  3. Все ссылки из предыдущего вопроса

Я написал код, а мне выдает какую-то ошибку

Что пошло не так? Устранение ошибок JavaScript

Советы:

  1. Если не понимаете английского — пользуйтесь словарем/переводчиком.
  2. Не стесняйтесь гуглить текст ошибки.
  3. Если не работает большой кусок кода — попробуйте отладить его часть.

Я не знаю, как подступиться к задаче

  1. Мысленно пройдись последовательно по коду, записывая значения переменных и результат работы.
  2. Постарайся разбить большую задачу на маленькие подзадачи и решать их по отдельности — так гораздо проще. Или упрости задачу до варианта, который ты можешь решить, а потом дорабатывай ее до необходимых требований.

Я не знаю, как работать с римскими числами

Воспользуйтесь преобразованием римских чисел в арабские. Как это сделать можно легко найти в интернете.

Успехов!

Сегодня сделаем простейший калькулятор на JavaScript, но не просто так, а с умыслом. Позднее мы представим, что мы тестировщики, и попробуем протестировать этот калькулятор. Вернее, не протестировать, а дико сломать.

Что делаем

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

Логика работы

Так как это простой калькулятор, то поступим так:

  1. Сделаем поле ввода для первого числа.
  2. Под ним разместим 4 кнопки с математическими действиями.
  3. Потом сделаем поле ввода для второго числа.
  4. И внизу будет кнопка «Посчитать».

Размещаем кнопки и поля ввода на странице

Разместим кнопки с полями на странице, а потом будем писать скрипт.

<!DOCTYPE html>
<html lang="ru">
<head>
	<meta charset="utf-8">
	<title>Калькулятор</title>
</head>
<body>
	<!-- поле ввода первого числа -->
	<input id="num1" />

	<!-- блок с кнопками -->
	<div id="operator_btns">
	  <button id="plus" >+</button>
	  <button id="minus" >-</button>
	  <button id="times" >x</button>
	  <button id="divide" >:</button>
	</div>

	<!-- поле ввода второго числа -->
	<input id="num2" />
	<br>

	<!-- кнопка для рассчётов -->
	<button >Посчитать</button>

</body>
</html>
Простой калькулятор на JavaScript
Первый подход к странице.

Обрабатываем нажатия на кнопки математических действий

Сейчас у нас есть 4 кнопки, но нажимать их бесполезно — всё равно ничего не произойдёт, потому что нет обработчиков нажатий. Но что нам прописывать в обработчике?

Первый вариант — привязать к каждой кнопке свою функцию, а потом для каждой операции выполнять свои действия внутри этого обработчика. Но раз у нас есть кнопка «Посчитать», то нам придётся при нажатии на неё из этих четырёх функций вытаскивать действие и нужные команды, запоминать выбранное и как-то использовать в вычислениях. Сложно и громоздко.

Второй вариант — просто записывать в какую-то переменную, какая кнопка была нажата. А потом, при нажатии «Посчитать», просто смотреть в эту переменную и выполнять соответствующее действие. Так и поступим.

👉 Воспользуемся хитростью, про которые многие забывают: в обработчике onclick необязательно писать только функцию — туда можно отправить любую JS-команду. Главное, не забыть потом в скрипте предусмотреть эту переменную, которую мы используем.

<!-- блок с кнопками -->
<div id="operator_btns">
  <button id="plus" onclick="op='+'">+</button>
  <button id="minus" onclick="op='-'">-</button>
  <button id="times" onclick="op='*'">x</button>
  <button id="divide" onclick="op='/'">:</button>
</div>

Пишем скрипт

Сам скрипт тоже будет простой:

  1. Берём два числа.
  2. Смотрим, какое значение в переменной для выбранного действия.
  3. В зависимости от этого вычисляем результат.
<script>
  // переменная, в которой хранится выбранное математическое действие
  var op; 

  // функция расчёта
  function func() {
  	// переменная для результата
    var result;
    // получаем первое и второе число
    var num1 = Number(document.getElementById("num1").value);
    var num2 = Number(document.getElementById("num2").value);
    // смотрим, что было в переменной с действием, и действуем исходя из этого
    switch (op) {
      case '+':
        result = num1 + num2;
        break;
      case '-':
        result = num1 - num2;
        break;
      case '*':
        result = num1 * num2;
        break;
      case '/':
        result = num1 / num2;
        break;
    }

  }
</script>

Сразу привяжем функцию func() к нажатию на кнопку «Посчитать»:

<button onclick="func()">Посчитать</button>

Выводим результат

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

Это — добавим на страницу после кнопки с расчётом:

<p id="result"></p>

А это — в функцию func(), чтобы она сразу отправляла результат на страницу:

document.getElementById("result").innerHTML = result;

Собираем всё вместе и смотрим результат

<!DOCTYPE html>
<html lang="ru">
<head>
	<meta charset="utf-8">
	<title>Калькулятор</title>
</head>
<body>
	<!-- поле ввода первого числа -->
	<input id="num1" />

	<!-- блок с кнопками -->
	<div id="operator_btns">
	  <button id="plus" onclick="op='+'">+</button>
	  <button id="minus" onclick="op='-'">-</button>
	  <button id="times" onclick="op='*'">x</button>
	  <button id="divide" onclick="op='/'">:</button>
	</div>

	<!-- поле ввода второго числа -->
	<input id="num2" />
	<br>

	<!-- кнопка для расчётов -->
	<button onclick="func()">Посчитать</button>

	<!-- здесь будет результат -->
	<p id="result"></p>

	<!-- наш скрипт -->
	<script>
	  // переменная, в которой хранится выбранное математическое действие
	  var op; 

	  // функция расчёта
	  function func() {
	  	// переменная для результата
	    var result;
	    // получаем первое и второе число
	    var num1 = Number(document.getElementById("num1").value);
	    var num2 = Number(document.getElementById("num2").value);
	    // смотрим, что было в переменной с действием, и действуем исходя из этого
	    switch (op) {
	      case '+':
	        result = num1 + num2;
	        break;
	      case '-':
	        result = num1 - num2;
	        break;
	      case '*':
	        result = num1 * num2;
	        break;
	      case '/':
	        result = num1 / num2;
	        break;
	    }

	    // отправляем результат на страницу
	    document.getElementById("result").innerHTML = result;
	  }
	</script>

</body>
</html>

Отлично, калькулятор работает и складывает всё как нужно! Мы выполнили свою задачу — быстро запилили калькулятор на JavaScript, можно закрывать задачу в таск-трекере и браться за новую. 

Посмотреть калькулятор на странице проекта.

Что дальше

Дальше мы этот код отправим тестировщикам — вряд ли они в нём найдут что-то критичное или вообще какие-то ошибки, но правила есть правила. А если тестировщики тут что-то найдут, мы обязательно расскажем об этом в новой статье.

Попробуйте сами побыть тестировщиком и протестировать эту программу, а результатами тестирования поделитесь в комментариях.

Вёрстка:

Кирилл Климентьев

Время на прочтение
4 мин

Количество просмотров 101K

Доброго времени суток, друзья!

В этой статье мы с вами, как следует из названия, напишем простой калькулятор на JavaScript.

Желание написать калькулятор возникло у меня после просмотра одного туториала, посвященного созданию «simple calculator», который оказался далеко не симпл и толком ничего не умел делать.

Наш калькулятор будет true simple (42 строки кода, включая пробелы между блоками), но при этом полнофункциональным и масштабируемым.

Для расчетов будет использоваться эта замечательная библиотека (Math.js).

Без дальнейших предисловий, приступаем к делу.

Наша разметка выглядит так:

<!-- head -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/6.6.4/math.js"></script>

<!-- body -->
<div class="calculator">
    <output></output>
</div>

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

Подключаем стили:

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  height: 100vh;
  background: radial-gradient(circle, skyblue, steelblue);
  display: flex;
  justify-content: center;
  align-items: center;
}

.calculator {
  width: 320px;
  height: 480px;
  background: #eee;
  border-radius: 5px;
  box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.2), -2px -2px 3px rgba(0, 0, 0, 0.2);
}

output {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 300px;
  height: 40px;
  background: #fff;
  margin: 10px auto;
  border-radius: 5px;
  font-size: 1.4em;
  font-weight: bold;
  box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.3),
    inset -1px -1px 1px rgba(0, 0, 0, 0.3);
}

.keyboard {
  height: 440px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-evenly;
  align-items: flex-start;
}

button {
  margin: 0.5em 1em;
  width: 40px;
  height: 40px;
  display: flex;
  justify-content: center;
  align-items: center;
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1em;
  font-weight: bold;
}

Вот что мы имеем на данный момент:

Кнопки будут генерироваться программно.

Переходим к скрипту.

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

const output = document.querySelector('output')

const div = document.createElement('div')
div.classList.add('keyboard')
document.querySelector('.calculator').appendChild(div)

Наша строка с символами выглядит так:

'C CE % / 7 8 9 * 4 5 6 - 1 2 3 + 0 ( ) ='

Преобразуем данную строку в массив и создаем кнопки:

// разделителем служит пустая строка
// можно было бы обойтись без пробелов, если бы у нас не было "CE"
'C CE % / 7 8 9 * 4 5 6 - 1 2 3 + 0 ( ) ='.split(' ')
    // пробегаемся по массиву
    // для каждого символа
    // создаем кнопку с помощью строкового литерала
    // записываем значение символа в атрибут "value" кнопки
    .map(symbol => {
        div.insertAdjacentHTML('beforeend', `<button value="${symbol}">${symbol}</button>`)
    })

Находим созданные кнопки и добавляем к ним обработчик события «клик»:

document.querySelectorAll('button').forEach(button => {
    button.addEventListener('click', function () {
        // по клику вызывается функция со значением кнопки в качестве параметра
        calc(this.value)
    })
})

Мы также хотим иметь возможность вводить символы с помощью клавиатуры. Для этого нам необходимо добавить обработчик события «нажатие клавиши» к объекту «Document» или «Window», затем отфильтровать ненужные значения свойства «ключ» клавиши, например, с помощью регулярного выражения:

document.addEventListener('keydown', event => {
    if ((event.key).match(/[0-9%/*-+()=]|Backspace|Enter/)) calc(event.key)
})

Метод «match» в данном случае играет роль фильтра: он не позволяет передавать функции «calc» аргумент, не соответствующий заданному в нем условию.

Само условие звучит так: если значением event.key является один из символов, указанных в квадратных скобках ([]; цифра от 0 до 9, знаки деления, умножения, сложения, вычитания, открывающая, закрывающая круглые скобки или знак равенства; обратная косая черта — экранирование) или (| — альтерация) Backspace, или Enter, то вызываем calc с event.key в качестве параметра, иначе ничего не делаем (Shift также успешно отбрасывается).

Наша главная (и единственная) функция «calc» выглядит следующим образом (код следует читать снизу вверх):

// функция принимает значение кнопки или ключ клавиши
function calc(value) {
    // если нажат знак равенства или Enter
    if (value.match(/=|Enter/)) {
        // пробуем выполнить операцию
        try {
            // вычисляем значение строки
            // это возможно благодаря методу "evaluate" объекта "math"
            // Math.trunc используется для округления до целого числа
            output.textContent = Math.trunc(math.evaluate(output.textContent))
            
        // если операцию выполнить невозможно
        } catch {
            // сохраняем значение поля
            let oldValue = output.textContent
            // создаем новую переменную
            let newValue = 'недопустимое выражение'
            // выводим значение новой переменной в поле
            output.textContent = newValue
            // через полторы секунды возвращаем полю старое значение
            setTimeout(() => {
                output.textContent = oldValue
            }, 1500)
        }
        
    // если нажат символ "C"
    } else if (value === 'C') {
        // очищаем поле
        output.textContent = ''
    
    // если нажат символ "СЕ" или Backspace
    } else if (value.match(/CE|Backspace/)) {
        // уменьшаем строку на один символ
        output.textContent = output.textContent.substring(0, output.textContent.length - 1)
        
    // если нажата любая другая (отфильтрованная) кнопка или клавиша
    } else {
        // записываем ее значение в поле
        output.textContent += value
    }
}

В завершение, парочка слов о заявленной масштабируемости и полнофункциональности.

Метод «evaluate» (ранее «eval») и другие методы Math.js имеют очень большие возможности. Опираясь на эти возможности, мы можем легко расширить функционал нашего калькулятора, добавив в него новые символы и операторы, предусмотрев возможность работы с числами с плавающей точкой (регулируя количество знаков после запятой с помощью переключателя и метода «toFixed») и т.д.

Результат:

Код на GitHub.

Благодарю за внимание. Надеюсь, вы нашли для себя что-то полезное. Хороших выходных и счастливого кодинга.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

<script>

window.addEventListener('load', function OnWindowLoaded() {

    var signs = [

        '1', '2', '3', '+',

        '4', '5', '6', '-',

        '7', '8', '9', '/',

        '0', '=', '.', 'c'

    ];

    var calc = document.getElementById('calc');

    var textArea = document.getElementById('inputVal');

    signs.forEach(function (sign) {

        var signElement = document.createElement('div');

        signElement.className = 'btn';

        signElement.innerHTML = sign;

        calc.appendChild(signElement);

    });

    document.querySelectorAll('#calc-wrap .btn').forEach(function (button) {

        button.addEventListener('click', onButtonClick);

    });

    function onButtonClick(e) {

        if (e.target.innerHTML === 'c') {

            textArea.innerHTML = '0';

        } else if (e.target.innerHTML === '=') {

            textArea.innerHTML = eval(textArea.innerHTML);

        } else if (textArea.innerHTML === '0') {

            textArea.innerHTML = e.target.innerHTML;

        } else {

            textArea.innerHTML += e.target.innerHTML;

        }

    }

});

</script>

Инструкция от loftblog: https://youtu.be/VHGaBc9OcXU
Описание: https://loftblog.ru/material/11-pervaya-programma-kalkulyator-na-javascript/
Результат: https://projectcalculator1.github.io/ 

Определяем, какие функции нам понадобятся:

numberPress — отслеживать нажатие на клавиши с цифрами и получать число
operationPress — получать значения операторов
decimal — ввод десятичной точки
clear — очистка — полная (клавиша С) и последнего действия (клавиша СЕ)

Для поиска элементов используем методы:


document.querySelectorAll(«.class») — находит все элементы определённого класса, например, все кнопки с числами или все кнопки с операторами;
document.getElementById(«id») — находит уникальные элементы, имеющие свой id, который, как известно, на странице может быть только один. Например, знак «равно», десятичную точку, клавишу «С» и т.д

e.srcElement.id — свойство для распознавания кнопки по её id
e.target.textContent — свойство для получения текста кнопки

Для обхода всех кнопок используем цикл.

for(var i = 0; i < numbers.length; i++) {
    var number = numbers[i];
    number.addEventListener(«click», function(e){
        console.log(«Клик по кнопке с номером » + e.target.textContent)
    })
};

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

Отслеживание кликов по кнопкам осуществляет функция

 number.addEventListener(«click», function(e){
        …
    })

Дальше. Переписываем безымянную функцию function(e) в коде выше на определённую нами ранее функцию numberPress.

При этом, если написать функцию со скобками, то это будет сразу вызов функции и она сработает при загрузке страницы:

number.addEventListener(«click», numberPress())

Так как нам нужно, чтобы функция срабатывала только по клику, то пишем название функции без скобок

number.addEventListener(«click», numberPress)

А вызов функции будет ниже:

function numberPress() {
    …
}

Теперь интересный момент — как отличить по какой кнопке был сделан клик

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

Напишем вот такой код

ce.addEventListener(«click», function(e){
    console.log(e)
});

Здесь в console.log вызывается событие е, которое возникает при каждом клике
При клике по кнопке в консоли мы видим объект MouseEvent, в котором много разных свойств, в том числе и srcElement, содержащее информацию об элементе, в том числе и его id

Следующая функция выведет в консоль id элемента

ce.addEventListener(«click», function(e){
    console.log(e.srcElement.id)
});

Переписываем код следующим образом:

for(var i = 0; i < clearBtns.length; i++) {
    var clearBtn = clearBtns[i];
        clearBtn.addEventListener(«click», function(e){
        clear(e.srcElement.id);
        });
    };


function clear(id) {
        console.log(«Клик по » + id)
    };

Здесь мы вначале вызываем анонимную функцию function(e){…}, так как нам нужен её аргумент е — событие, потом внутри прописываем нашу функцию clear(e.srcElement.id); аргументом которой является значение id элемента, затем запускаем эту функцию с аргументом id (название произвольное), но так как выше мы уже определили, что аргумент функции e.srcElement.id, получается, что id = e.srcElement.id. Соответственно, вызов console.log(«Клик по » + id) возвращает нам «Клик по с» или «Клик по се», смотря на какую кнопку мы кликаем.

Дальше делаем то же самое для цифр и операторов, но так как нам нужно их содержание, вместо e.srcElement.id используем свойство e.target.textContent

Получится примерно так:

for(var i = 0; i < numbers.length; i++) {
    var number = numbers[i];
    number.addEventListener(«click», function(e){
        numberPress(e.target.textContent);
    });
};


function numberPress(number) {
        console.log(«Клик по кнопке с номером » + number)
    }

Итого, к 44 минуте видео мы научились отслеживать клики по кнопкам и распознавать их и переходим к программированию.

Теперь нам нужно написать функции для ввода чисел.

Общие структуры функций:

Функция, которая отражает введенное число на экране калькулятора:

function numberPress (number) {

if (условие) { //ввод нового значение и меняем значение флага}

else {

if (условие) { //стирает 0 с дисплея}

else { //добавляет цифру к числу на экране}

     }  

};

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

function operation (op) {

//создаем локальную переменную памяти

if (условия) { //сохраняем значение на экране в переменную памяти}

else { //говорим переменной памяти о том, что мы вводим новое число}

if (условие с +) { //выполнение операции}

else if (условие с -) { //выполнение операции}

else if (условие с *) { //выполнение операции}

else if (условие с /) { //выполнение операции}

else { //действия с глобальной и локальной памятью};  

//вывод результата

//сохранение текущей операции

};

!Функция преобразования строки к числу с плавающей точкой parseFloat().

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

Функция добавления десятичной точки:

function decimal (argument) {

//создаем локальную переменную

if (условие) { //добавляем 0.}

else { 

if (условие) { //если не существует символа ‘.’ в строке – добавляй точку };

};  

};

Функция обработки кнопок очищения C и СЕ:

function clear (argument) {

if (условие с се) { //удаление введённого числа с дисплея}

else if (условие с с) { //очищения дисплея };

};

Функции в деталях:

Функция, которая отражает введенное число на экране калькулятора:

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

Глобальные переменные:

MemoryCurrentNumber = 0, // вводимое в данный момент число

MemoryNewNumber = false, // флаг, переключатель, показывающий вводим мы новое число, или ещё прежнее. Новое число будет после того, как нажали на оператор, то есть, функция operation должна этот флаг менять

MemoryPendingOperation = «»; // ожидаемая операция, на которую нажали перед вводом нового числа

Дальше. В функцию numberPress добавляем строку display.value = number;

function numberPress(number) {

        display.value = number;

        console.log(«Клик по кнопке с номером » + number)

    }

display.value — значение элемента display,

number — значение кнопки калькулятора, на которую мы нажали.

Теперь при кликам по кнопкам появляются цифры. Магия начинает работать )

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

Это не сложно:

function numberPress(number) {

        display.value += number;

        console.log(«Клик по кнопке с номером » + number)

    }

Но теперь новая цифра прибавляется и к нулю, который был введён раньше.

Добавляем условие:

function numberPress(number) {

        if(display.value === «0») {

            display.value = number;

        } else {

            display.value += number;

        }

     }

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

Перейдём к функции operation

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

Как только мы нажимаем на любой оператор, нам нужно чтобы программа запомнила уже введённое на дисплей число

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

localOperationMemory = display.value;

function operationPress(op) {

        localOperationMemory = display.value;

        if(MemoryNewNumber && MemoryPendingOperation !== «=») {

            display.value = MemoryCurrentNumber;

        } else {

            MemoryNewNumber = true;

            if (MemoryPendingOperation === «+») {

                MemoryCurrentNumber += +localOperationMemory;  

            } else if (MemoryPendingOperation === «-«) {

                MemoryCurrentNumber -= +localOperationMemory;  

            } else if (MemoryPendingOperation === «*») {

                MemoryCurrentNumber *= +localOperationMemory;  

            } else if (MemoryPendingOperation === «/») {

                MemoryCurrentNumber /= +localOperationMemory;  

            } else {

                MemoryCurrentNumber = +localOperationMemory;  

            }

            display.value = MemoryCurrentNumber;

            MemoryPendingOperation = op;

        };

      }

Кроме того, мы усовершенствовали функцию numberPress

function numberPress(number) {

        if(MemoryNewNumber) {

            display.value = number;

            MemoryNewNumber = false;

        } else {

            if(display.value === «0») {

                display.value = number;

            } else {

                display.value += number;

            };

        };

    };

Теперь наш калькулятор умеет считать.

Ура!

Осталось научить его понимать десятичную точку и научить стирать с экрана и памяти последнее действие или всё.

В этом практическом уроке я хочу показать вам реализацию калькулятора на чистом JavaScript. Также в ходе работы мы будем использовать Grid CSS и немного поговорим о безопасности нашего скрипта.

В качестве основы я буду использовать базовый HTML-каркас к которому подключен один CSS-файл style.css. Откроем его и напишем базовые стили для нашего проекта. На глобальном уровне изменим алгоритм блочной модели на значение border-box. А также сбросим внешние отступы
у элемента body.

* {
  box-sizing: border-box;
}

body {
  margin: 0;
}

Разметка калькулятора

Теперь давайте перейдем к разметке. Сам калькулятор я обозначу через тег <article>, поскольку это самодостаточный автономный компонент. И задам ему соответствующий класс calc:

<article class="calc">

</article>

Результат вычислений калькулятора мы будем выводить в элемент <output>, который и был для этого создан. Дадим ему класс cacl__result, а также идентификатор result для более простого обращения:

<article class="calc">
  <!-- Результат вычислений -->
  <output class="calc__result" id="result"></output>
</article>

Далее нам нужно определить кнопки нашего калькулятора. Для этого мы будем использовать элементы <button> с типом button и классом calc__btn. Всего нам понадобится 18 кнопок. Для быстрого их создания воспользуемся Emmet:

button[type=button].calc__btn*18

В результате мы получим следующую структуру:

<article class="calc">

  <!-- Результат вычислений -->
  <output class="calc__result" id="result"></output>

  <!-- Клавиши калькулятора -->
  <button class="calc__btn" type="button"></button>
  <button class="calc__btn" type="button"></button>
  <button class="calc__btn" type="button"></button>
  <button class="calc__btn" type="button"></button>

  <button class="calc__btn" type="button"></button>
  <button class="calc__btn" type="button"></button>
  <button class="calc__btn" type="button"></button>
  <button class="calc__btn" type="button"></button>

  <button class="calc__btn" type="button"></button>
  <button class="calc__btn" type="button"></button>
  <button class="calc__btn" type="button"></button>
  <button class="calc__btn" type="button"></button>  

  <button class="calc__btn" type="button"></button>
  <button class="calc__btn" type="button"></button>
  <button class="calc__btn" type="button"></button>    
  <button class="calc__btn" type="button">/</button>

  <button class="calc__btn" type="button"></button>
  <button class="calc__btn" type="button"></button>

</article>

Для удобства работы визуально мы разбили все кнопки в группы по 4 элемента. Именно столько кнопок будет содержать калькулятор в каждом ряду. Теперь давайте заполним их значениями.

В первом ряду у нас будут находится цифры 7, 8, 9 и оператор плюс +. Во втором — 4, 5, 6 и оператор минус -. В третьем — 1, 2, 3 и оператор умножения *. И в четвертом мы разместим 0, десятичную точку, кнопку с двумя нулями и оператор деления /.

Последний ряд у нас содержит всего 2 элемента. Первый из них будет кнопкой сброса, обозначим ее через заглавную C. А второй — оператором равно =:

<article class="calc">

  <!-- Результат вычислений -->
  <output class="calc__result" id="result"></output>

  <!-- Клавиши калькулятора -->
  <button class="calc__btn" type="button">7</button>
  <button class="calc__btn" type="button">8</button>
  <button class="calc__btn" type="button">9</button>
  <button class="calc__btn" type="button">+</button>

  <button class="calc__btn" type="button">4</button>
  <button class="calc__btn" type="button">5</button>
  <button class="calc__btn" type="button">6</button>
  <button class="calc__btn" type="button">-</button>

  <button class="calc__btn" type="button">1</button>
  <button class="calc__btn" type="button">2</button>
  <button class="calc__btn" type="button">3</button>
  <button class="calc__btn" type="button">*</button>  

  <button class="calc__btn" type="button">0</button>
  <button class="calc__btn" type="button">.</button>
  <button class="calc__btn" type="button">00</button>    
  <button class="calc__btn" type="button">/</button>

  <button class="calc__btn" type="button">C</button>
  <button class="calc__btn" type="button">=</button>

</article>

На этом с разметкой мы закончили и можем переходить к ее оформлению.

Стилизация калькулятора

Начнем мы с класса .calc:

  • установим ему ширину в 600px
  • зададим видимую границу
  • небольшой радиус в 10px
  • фоновую заливку
  • и внутренние поля в 20px
.calc {  
  width: 600px;
  border: solid 2px #555;
  border-radius: 10px;
  background-color: #888;
  padding: 20px;
}

Расположение кнопок

Теперь давайте займемся расположением кнопок. Поскольку мы имеем дело с двунаправленным макетом, идеальным кандидатом для него будет Grid CSS. В первую очередь, поменяем тип отображения нашего блока на grid и установим шаблон для колонок. В данном случае мне нужно получить 4 колонки одинаковой ширины. Укажу это при помощи функции repeat:

.calc {  
  width: 600px;
  border: solid 2px #555;
  border-radius: 10px;
  background-color: #888;
  padding: 20px;

  display: grid;
  grid-template-columns: repeat(4, 1fr);
}

Теперь я использую свойство grid-auto-rows, чтобы задать размер для всех рядов по умолчанию. Пусть он будет равным 80px. И последнее, что я хочу сделать, это задать отступы между нашими элементами. Для этого я использую свойство gap в значении 20px.

.calc {  
  width: 600px;
  border: solid 2px #555;
  border-radius: 10px;
  background-color: #888;
  padding: 20px;

  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 80px;
  gap: 20px;  
}

Выравнивание по центру экрана

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

body {
  margin: 0;
  min-height: 100vh;
  
  display: flex;
  justify-content: center;
  align-items: center; 
}

Блок с выводом результатов

Так уже гораздо лучше. Давайте перейдем к следующему блоку. А именно к блоку с выводом результата. В первую очередь, нам нужно растянуть его на всю ширину контейнера. И поскольку он является элементом сетки, мы легко можем это сделать.

Используем свойство grid-column и зададим его расположение от первой до последней линии:

.calc__result {
  grid-column: 1 / -1;
}

Как мы видим, наш блок удачно растянулся и сместил остальные элементы на новый ряд.

Давайте доработаем этот блок:

  • зададим ему фоновую заливку
  • поменяем цвет текста
  • установим размер шрифта
  • и внутренние поля
.calc__result {
  grid-column: 1 / -1;

  background-color: #333;
  color: #fff;
  font-size: 56px;
  padding: 10px;
}

На этом наш блок результатов готов.

Оформление кнопок

Клавиши калькулятора мы представили элементом button, у которого уже есть некоторые стили по умолчанию. Давайте их сбросим и назначим свои.

  • в первую очередь, уберем с кнопок обводку
  • добавим небольшой радиус
  • изменим цвет заливки
  • а также поменяем тип курсора

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

.calc__btn {
  border: none;
  border-radius: 5px;
  background-color: #eee;
  cursor: pointer;

  font-size: 30px;  
  box-shadow: 2px 3px 2px rgb(0 0 0 / 50%);
}

Не забудем определить и их поведение при наведении мыши. Например, пусть это будет небольшая прозрачность:

.calc__btn:hover {
  opacity: 0.9;
}

При нажатии мы также уменьшим нашу тень, чтобы создать видимость вдавленной кнопки:

.calc__btn:active {
  box-shadow: 1px 1px 2px rgb(0 0 0 / 50%);
}

Операторы

И последнее, что я хочу сделать — это как-то выделить наши кнопки с операторами. Примиксуем к ним модификаторы .calc__btn_operator. Кнопкам сброса и вычисления также добавим свои модификаторы:

  • .calc__btn_reset (рисэт)
  • и .calc__btn_equal (иквэл)
<article class="calc">

  <!-- Результат вычислений -->
  <output class="calc__result" id="result"></output>

  <!-- Клавиши калькулятора -->
  <button class="calc__btn" type="button">7</button>
  <button class="calc__btn" type="button">8</button>
  <button class="calc__btn" type="button">9</button>
  <button class="calc__btn calc__btn_operator" type="button">+</button>

  <button class="calc__btn" type="button">4</button>
  <button class="calc__btn" type="button">5</button>
  <button class="calc__btn" type="button">6</button>
  <button class="calc__btn calc__btn_operator" type="button">-</button>

  <button class="calc__btn" type="button">1</button>
  <button class="calc__btn" type="button">2</button>
  <button class="calc__btn" type="button">3</button>
  <button class="calc__btn calc__btn_operator" type="button">*</button>  

  <button class="calc__btn" type="button">0</button>
  <button class="calc__btn" type="button">.</button>
  <button class="calc__btn" type="button">00</button>    
  <button class="calc__btn calc__btn_operator" type="button">/</button>

  <button class="calc__btn calc__btn_reset" type="button">C</button>
  <button class="calc__btn calc__btn_equal" type="button">=</button>

</article>

Теперь перейдем к их оформлению. Пусть у операторов будет бледно-оранжевый фон:

.calc__btn_operator {
  background-color: #ffe2ae;
}

Для кнопки сброса мы установим красный фон и поменяем цвет текста на белый:

.calc__btn_reset {
  background-color: #ff5050;
  color: #fff;  
}

Кнопку вычисления мы сделаем синей, а цвет текста также поменяем на белый. Последнее, что нам осталось сделать, это растянуть кнопку «равно» до края сетки. Используем уже знакомое нам свойство grid-column и задаем расположение от второй до последней линии:

.calc__btn_equal { 
  background-color: #5b50ff; 
  color: #fff;  
  grid-column: 2 / -1;
}

Интерфейс нашего калькулятора готов, пора сделать его рабочим.

Логика калькулятора на JavaScript

Для этого я создам файл calc.js и подключу его в самом низу тела документа. Так мы будем точно уверены, что на момент исполнения сценария нам доступен весь DOM документа.

Делегирование

Для работы калькулятора мы должны отслеживать нажатие его кнопок. Первое что приходит на ум — обратиться ко всем элементам button, и повесить на них событие click. Однако, такая операция очень избыточна и не эффективна.

Вместо этого мы можем делегировать событие клика на сам элемент калькулятора:

  • находим его по классу calc
  • и вешаем нужное нам событие click
const calc = document.querySelector('.calc');

calc.addEventListener('click', function(event) {

});

Кто вызвал событие

Чтобы определить, какой именно элемент вызвал событие, мы можем использовать объект событий event, а конкретно его свойство target.
Для демонстрации давайте выведем его в консоль:

const calc = document.querySelector('.calc');

calc.addEventListener('click', function(event) {
  console.log(event.target);
});

Нажимая на кнопки, мы видим, что наше событие срабатывает успешно и в консоли выводятся правильные элементы.

Ограничение цели

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

const calc = document.querySelector('.calc');

calc.addEventListener('click', function(event) {
  if(!e.target.classList.contains('calc__btn')) return;

  console.log(event.target);
});

Теперь мы можем работать только с кнопками, исключая лишние элементы.

Значение кнопки

Поскольку значения кнопок хранятся в качестве их содержимого, мы будем получать их через свойство innerText. Для дальнейшего использования запишем это значение в переменную value:

const calc = document.querySelector('.calc');

calc.addEventListener('click', function(event) {
  if(!e.target.classList.contains('calc__btn')) return;

  let value = event.target.innerText;
});

Вывод значений в строку результатов

Теперь мы можем обратиться к блоку result, и выводить в него полученные значения. Для этого мы также используем свойство innerText:

const calc = document.querySelector('.calc');
const result = document.querySelector('#result');

calc.addEventListener('click', function(event) {
  if(!e.target.classList.contains('calc__btn')) return;

  let value = event.target.innerText;

  result.innerText += value;
});

Сброс и вычисление

Последнее, что нам осталось сделать это реализовать логику сброса и вычисления, потому что сейчас эти кнопки просто выводят свои значения как и другие. Для этого я буду использовать условную конструкцию switch по переменной value.

При значении C мы будем записывать в блок результата пустую строку. А по знаку равенства производить вычисления. Для этого я использую функцию eval(), которая выполняет переданный ей JavaScript-код в виде строки. В нашем случае это содержимое строки result. Также я использую метод toFixed() со значением два, чтобы оставлять только 2 знака после десятичной точки.

Ну а поведение остальных клавиш мы сделаем операцией по умолчанию:

const calc = document.querySelector('.calc');
const result = document.querySelector('#result');

calc.addEventListener('click', function(event) {
  if(!e.target.classList.contains('calc__btn')) return;

  let value = event.target.innerText;

  switch(value) {
    case 'C':
      result.innerText = '';
      break;  

    case '=':
      result.innerText = eval(result.innerText).toFixed(2);
      break;    

    default:
      result.innerText += value;
  }
});

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

Вопрос безопасности

Теперь давайте немного поговорим о безопасности нашего скрипта. Для вычисления выражения мы используем функцию eval(), которая считается крайне не безопасной, поскольку позволяет выполнить произвольный JavaScript.

Потенциально злоумышленник может передать в него какой-то вредоносный код. Например, давайте откроем консоль, и заменим содержимое клавиши, на команду calc.remove(). Теперь, если мы нажмем на кнопку равно, наш калькулятор будет удален. Однако, это произойдет только в браузере у самого злоумышленника. Другие пользователи никак от этого не пострадают. Тоже самое, мы могли бы сделать и просто, выполнив эту команду в консоли.

Поскольку наш калькулятор не использует никаких пользовательских данных, функция eval() здесь не представляет опасности. Тем не менее,
мы можем добавить еще один слой защиты, просто проверяя выражение на допустимые символы.

Для этого я буду использовать метод search, который выводит позицию первого совпадения с регулярным выражением. В регулярном выражении, мы просто будем искать все кроме цифр и наших операторов. Если совпадений не будет, то метод search() вернет нам значение -1. В противном случае мы просто выходим из функции:

const calc = document.querySelector('.calc');
const result = document.querySelector('#result');

calc.addEventListener('click', function(event) {
  if(!e.target.classList.contains('calc__btn')) return;

  let value = event.target.innerText;

  switch(value) {
    case 'C':
      result.innerText = '';
      break;  

    case '=':   
      // Проверка выражения
      if(result.innerText.search(/[^0-9*/+-]/mi) != -1) return;
      
      // Исполнение выражения
      result.innerText = eval(result.innerText).toFixed(2);
      break;    

    default:
      result.innerText += value;
  }
});

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

Cover image for Calculator Function using JavaScript 🚀🚀

How to create calculator function in JavaScript??

Yes, Today we are making a JavaScript function which is return some mathematics output.

So, let’s start with JavaScript code.

(1) Let’s make a JavaScript
file and give any name
here I am giving index.js.
(Note:- We must need a
html file to run our JS
code in browser)

(2) Next step make a function
name calculator() in js
file. And pass three
parameter x, y and o.
Alt Text

(3) Parameters explanation :-
(a) x is a first number
(b) y is a second number
(c) o is a operator

(4) We are using switch
statement as shown in
following code.

img2

(4) Let’s understand above
code :-
(a) first pass o
parameter because it
will decide which
mathematics operation
will conduct. o is
String and x and y
number
(b) If any user call this
function by passing three
parameters like
calculator(2,3,’+’) then
the first case is
executed.
(c) When anyone not enter
valid input the it will
return «enter valid
numbers».

(5) Let’s call the above
function and see output.
img3

👉 Happy Coding…
🙏 Thank you for reading…

Понравилась статья? Поделить с друзьями:

Не пропустите и эти статьи:

  • Как написать калькулятор на java для новичков
  • Как написать калькулятор на html
  • Как написать калькулятор на c windows forms
  • Как написать калькулятор на android studio
  • Как написать каланхоэ

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии