Это вторая часть треховного урока о создании калькулятора. К концу этих трех уроков вы должны получить калькулятор, который функционирует точно так же, как калькулятор iPhone (без +/- и процентные функции).
Примечание: пожалуйста, убедитесь, что вы закончите первая часть перед началом этой статьи.
Вы собираетесь научиться кодировать ключевые случаи, чтобы сделать ваш калькулятор устойчивым к странным узоре ввода в этом уроке.
Для этого вы должны представить нарушитель спокойствия, который пытается сломать свой калькулятор, ударяя ключи в неправильном порядке. Давайте назовем это нарушение удаления тима.
Тим может ударить эти ключи в любом порядке:
- Номер ключ (0-9)
- Ключ оператора (+, -, ×, ÷)
- Десятичный ключ
- Равный ключ
- Очистить ключ
Что произойдет, если Тим попадает в десятичный ключ
Если Тим попадает в десятичную клавишу, когда дисплей уже показывает десятичную точку, ничего не должно произойти.
Ничего не происходит, когда пользователь попадает в десятичную клавишу, когда дисплей уже показывает десятичную точку
Ничто не должно происходить, даже если предыдущий ключ не является десятичным ключом
Здесь мы можем проверить отображаемый номер содержит Отказ с включает в себя метод.
включает в себя Проверяет строки для данного матча. Если строка найдена, она возвращает правда ; Если нет, он возвращает ложь Отказ Примечание: включает в себя чувствителен к регистру
// Example of how includes work.
const string = 'The hamburgers taste pretty good!'
const hasExclaimation = string.includes('!')
console.log(hasExclaimation) // true
// Do nothing if string has a dot
if (!displayedNum.includes('.')) {
display.textContent = displayedNum + '.'
}
Далее, если TIM попадает в десятичную клавишу после удара ключа оператора, дисплей должен показать 0 .
Дисплей должен показать “0. ” Если пользователь попадает в десятичный ключ после оператора
Здесь нам нужно знать, является ли предыдущий ключ оператором. Мы можем сказать, проверив пользовательский атрибут, Данные - предыдущий ключ-тип Мы устанавливаем на предыдущем уроке.
Данные - предыдущий ключ-тип еще не завершен. Правильно идентифицировать, если previekeytype это оператор, нам нужно обновить previekeytype Для каждого нажатия клавиши.
if (!action) {
// ...
calculator.dataset.previousKey = 'number'
}
if (action === 'decimal') {
// ...
calculator.dataset.previousKey = 'decimal'
}
if (action === 'clear') {
// ...
calculator.dataset.previousKeyType = 'clear'
}
if (action === 'calculate') {
// ...
calculator.dataset.previousKeyType = 'calculate'
}
Как только у нас есть правильный previekeytype , мы можем использовать его, чтобы проверить, является ли предыдущий ключ оператором.
if (action === 'decimal') {
if (!displayedNum.includes('.')) {
display.textContent = displayedNum + '.'
} else if (previousKeyType === 'operator') {
display.textContent = '0.'
}
calculator.dataset.previousKeyType = 'decimal'
}
Что произойдет, если Тим попадает в ключ оператора
Во-первых, если TIM попадает в ключ оператора, первый ключ оператора должен загореться. (Мы уже были покрыты для этого края, но как? Посмотрите, можете ли вы определить, что мы сделали).
Ключ оператора должен загореться, если это первый ключ.
Во-вторых, ничто не должно произойти, если TIM бьет тот же операторский ключ несколько раз. (Мы уже были покрыты для этого пограничного случая).
ПРИМЕЧАНИЕ. Если вы хотите предоставить лучший UX, вы можете показать оператору снова нажав снова и снова с некоторыми изменениями CSS. Мы не делали этого здесь, потому что я взял записал все GIF, прежде чем я смогу это исправить.
Клавиша оператора остается в депрессии, если щелкать в несколько раз
В-третьих, если TIM ударит другой ключ оператора после удара первого ключа оператора, следует выпустить первый операторский ключ; Второй ключ оператора должен быть в депрессии. (Мы также охватываем этот край этот край; но как?).
Новый ключ оператора должен быть в депрессии
В-четвертых, если Тим попадает в число, оператор, номер и другой оператор, в этом порядке дисплей должен быть обновлен до расчетного значения.
Нажав на оператор, когда номера хранятся в калькуляторе приводит к расчету
Это означает, что нам нужно использовать рассчитать Функция, когда FirstValue , оператор и SecondValue существуют.
if (
action === 'add' ||
action === 'subtract' ||
action === 'multiply' ||
action === 'divide'
) {
const firstValue = calculator.dataset.firstValue
const operator = calculator.dataset.operator
const secondValue = displayedNum
// Note: It's sufficient to check for firstValue and operator because secondValue always exists
if (firstValue && operator) {
display.textContent = calculate(firstValue, operator, secondValue)
}
key.classList.add('is-depressed')
calculator.dataset.previousKeyType = 'operator'
calculator.dataset.firstValue = displayedNum
calculator.dataset.operator = action
}
Хотя мы можем рассчитать значение, когда клавиша оператора нажала во второй раз, мы также представили ошибку в данный момент-дополнительные клики на клавише оператора рассчитывают значение, когда он не должен.
Ошибка: последующие клики на операторе выполняют расчет, когда он не должен
Чтобы предотвратить вычисление калькулятора на последующие клики на ключ оператора, нам нужно проверить, если previekeytype это оператор; Если это так, мы не выполняем расчет.
if (
firstValue &&
operator &&
previousKeyType !== 'operator'
) {
display.textContent = calculate(firstValue, operator, secondValue)
}
Пятый, после того, как ключ оператора рассчитывает число, если Тим попадает в число, за которым следует другой оператор, оператор должен продолжаться с расчетом, как это: 8 - , 7 - , 5 - Отказ
Калькулятор должен быть в состоянии продолжить расчет, когда пользователь нажимает на номера, а затем операторы, за которыми следует номера, а затем операторы и так далее.
Прямо сейчас наш калькулятор не может принимать последовательные расчеты. Второе расчетное значение неверно. Вот что у нас есть: 99 - , 98 - Отказ
Рассчитанные значения неверны. Второе рассчитанное значение должно быть 97 вместо 0
Второе значение вычисляется неправильно, потому что мы кормили неправильные значения в рассчитать функция. Давайте пройдем несколько фотографий, чтобы понять, что делает наш код.
Понимание нашей расчетной функции
Во-первых, давайте скажем, пользователь нажимает на номер 99. На данный момент ничто не зарегистрировано в калькуляторе пока.
Когда пользователь ударяет числа, калькулятор не регистрирует FirstValue. или оператор
Во-вторых, давайте скажем, пользователь нажимает подчитанный оператор. После того, как они нажимают на вычитанный оператор, мы устанавливаем FirstValue до 99. Мы устанавливаем и Оператор вычесть.
FirstValue. и оператор установлены после кнопки оператора щелкнул
В-третьих, скажем, пользователь нажимает на второе значение; На этот раз это 1. На данный момент отображаемый номер обновляется до 1, но наш FirstValue , Оператор и SecondValue остается неизменной.
Отображать обновления до 1, но FirstValue. и оператор остается 99 и вычесть
В-четвертых, пользователь нажимает на вычесть снова. Сразу после того, как они нажимают вычитание, прежде чем мы рассчитаем результат, мы устанавливаем SecondValue. как отображаемый номер.
Мы установили SecondValue. до 1
В-пятых, мы выполняем расчет с FirstValue 99, Оператор вычесть, а SecondValue 1 Результат 98.
После того, как результат будет рассчитан, мы установим дисплей к результату. Тогда мы устанавливаем Оператор вычесть, а FirstValue до предыдущего отображаемого номера.
После расчета первым образом установлено значение представленная
Ну, это ужасно не так! Если мы хотим продолжить расчет, нам нужно обновить FirstValue с рассчитанным значением.
Обновления рассчитанного значения как FirstValue.
const firstValue = calculator.dataset.firstValue
const operator = calculator.dataset.operator
const secondValue = displayedNum
if (
firstValue &&
operator &&
previousKeyType !== 'operator'
) {
const calcValue = calculate(firstValue, operator, secondValue)
display.textContent = calcValue
// Update calculated value as firstValue
calculator.dataset.firstValue = calcValue
} else {
// If there are no calculations, set displayedNum as the firstValue
calculator.dataset.firstValue = displayedNum
}
key.classList.add('is-depressed')
calculator.dataset.previousKeyType = 'operator'
calculator.dataset.operator = action
С помощью этого исправления последовательные расчеты, выполняемые клавишами оператора, теперь должны быть правильными.
Последовательные расчеты, выполненные с помощью ключа оператора, теперь правильно
Что произойдет, если Тим попадает в равный ключ?
Во-первых, ничего не должно произойти, если Тим попадает в равный ключ перед любыми операторами клавиш,
Калькулятор должен показать ноль, если равный ключ ударил первым
Когда не требуется расчет, дисплей остается прежним
Мы знаем, что ключи оператора еще не щелкнулись Если FirstValue не установлен на номер. Мы можем использовать эти знания для предотвращения расчета равных.
if (action === 'calculate') {
const firstValue = calculator.dataset.firstValue
const operator = calculator.dataset.operator
const secondValue = displayedNum
if (firstValue) {
display.textContent = calculate(firstValue, operator, secondValue)
}
calculator.dataset.previousKeyType = 'calculate'
}
Во-вторых, если Тим попадает в число, а затем оператор, за которым следует равный, калькулятор должен рассчитать такое результат, что:
2 + =->2 +2 - =->2 -2 × =->2 ×2 ÷ =->2 ÷
Калькулятор должен лечить первое и второе значения в качестве одних и тех же числей, если оно отсутствует значение
Мы уже сделали этот странный ввод во внимание. Можете ли вы понять почему?:)
В-третьих, если TIM попадает в равный ключ после завершения расчета, другой расчет должен быть выполнен снова. Вот как следует прочитать расчет:
- Тим хиты ключ 5 – 1
- Тим хиты равны. Расчетное значение –
5 - - Тим хиты равны. Расчетное значение –
4 - - Тим хиты равны. Расчетное значение –
3 - - Тим хиты равны. Расчетное значение –
2 - - Тим хиты равны. Расчетное значение –
1 -
Когда пользователь несколько раз попадает в равный ключ, калькулятор должен продолжать вычислять
К сожалению, наш калькулятор портит этот расчет. Вот что показывает наш калькулятор:
- Тим хиты ключ 5 – 1
- Тим хиты равны. Расчетное значение –
4. - Тим хиты равны. Расчетное значение –
1.
Равный ключевой последовательный расчет дает неправильный результат
Исправлять расчет
Во-первых, скажем, наш пользователь мы нажимаем 5. На данный момент ничто не зарегистрировано в калькуляторе пока.
Когда пользователь нажал на первый номер, калькулятор не регистрирует FirstValue. или оператор
Во-вторых, давайте скажем, пользователь нажимает подчитанный оператор. После того, как они нажимают на вычитанный оператор, мы устанавливаем FirstValue до 5. Мы устанавливаем и Оператор вычесть.
FirstValue. и оператор установлены после кнопки оператора щелкнул
В-третьих, пользователь нажимает на второе значение. Допустим, это 1. На данный момент отображаемый номер обновляется до 1, но наш FirstValue , Оператор и SecondValue остается неизменной.
Отображать обновления до 1, но FirstValue. и оператор остается 5 и вычесть
В-четвертых, пользователь нажимает на равный ключ. Сразу после того, как они нажимают на равных, но перед расчетом мы устанавливаем SecondValue. как представленная
Мы установили SecondValue. в виде представленная
В-пятых, калькулятор рассчитывает результат 5 - 1 и дает 4 Отказ Результат обновляется на дисплей. FirstValue и Оператор Переносится вперед к следующему расчету, поскольку мы не обновили их.
FirstValue. и оператор используются для следующей операции
Шестой, когда пользователь снова попадает равна, мы установили SecondValue. к ПоказательНюм до расчета.
Еще раз, отображаемое NUM устанавливается как SecondValue. до расчета
Вы можете сказать, что здесь не так.
Вместо SecondValue. Мы хотим набор FirstValue к отображению номера.
if (action === 'calculate') {
let firstValue = calculator.dataset.firstValue
const operator = calculator.dataset.operator
const secondValue = displayedNum
if (firstValue) {
if (previousKeyType === 'calculate') {
firstValue = displayedNum
}
display.textContent = calculate(firstValue, operator, secondValue)
}
calculator.dataset.previousKeyType = 'calculate'
}
Мы также хотим нести предыдущий SecondValue в новый расчет. Для SecondValue Чтобы сохранить следующую расчет, нам нужно хранить его в другом пользовательском атрибуте. Давайте назовем этот пользовательский атрибут ModValue (обозначает значение модификатора).
if (action === 'calculate') {
let firstValue = calculator.dataset.firstValue
const operator = calculator.dataset.operator
const secondValue = displayedNum
if (firstValue) {
if (previousKeyType === 'calculate') {
firstValue = displayedNum
}
display.textContent = calculate(firstValue, operator, secondValue)
}
// Set modValue attribute
calculator.dataset.modValue = secondValue
calculator.dataset.previousKeyType = 'calculate'
}
Если previekeytype это рассчитать мы знаем, что мы можем использовать Calculator.Dataset.modvalue. как SecondValue. . Как только мы это знаем, мы можем выполнить расчет.
if (firstValue) {
if (previousKeyType === 'calculate') {
firstValue = displayedNum
secondValue = calculator.dataset.modValue
}
display.textContent = calculate(firstValue, operator, secondValue)
}
С этим у нас есть правильный расчет, когда ключевой ключ нажимается последовательно.
Последовательные расчеты, сделанные равным ключом сейчас фиксируется
Вернуться к ключевому ключу
В-четвертых, если Тим попадает в десятичный ключ или номер числа после клавиши калькулятора, дисплей должен быть заменен на 0 или новый номер соответственно.
Здесь вместо того, чтобы просто проверять, если previekeytype это оператор , нам также нужно проверить, это рассчитать Отказ
if (!action) {
if (
displayedNum === '0' ||
previousKeyType === 'operator' ||
previousKeyType === 'calculate'
) {
display.textContent = keyContent
} else {
display.textContent = displayedNum + keyContent
}
calculator.dataset.previousKeyType = 'number'
}
if (action === 'decimal') {
if (!displayedNum.includes('.')) {
display.textContent = displayedNum + '.'
} else if (
previousKeyType === 'operator' ||
previousKeyType === 'calculate'
) {
display.textContent = '0.'
}
calculator.dataset.previousKeyType = 'decimal'
}
В-пятых, если Тим попадает в ключ оператора сразу после равного ключа, калькулятор не должен рассчитывать.
Ключи оператора не должны выполнять расчеты, если они нажимают после равного ключа
Для этого мы проверяем, если previekeytype это рассчитать Перед выполнением расчетов с операторами ключей.
if (
action === 'add' ||
action === 'subtract' ||
action === 'multiply' ||
action === 'divide'
) {
// ...
if (
firstValue &&
operator &&
previousKeyType !== 'operator' &&
previousKeyType !== 'calculate'
) {
const calcValue = calculate(firstValue, operator, secondValue)
display.textContent = calcValue
calculator.dataset.firstValue = calcValue
} else {
calculator.dataset.firstValue = displayedNum
}
// ...
}
Что произойдет, если Тим попадает в четкий ключ?
Clear Key имеет два использования:
- Все ясно (обозначено
AC) Очищает все и сбрасывает калькулятор к своему первоначальному состоянию. - Очистить запись (обозначается
CE) Очищает текущую запись. Он сохраняет предыдущие числа в памяти.
Когда калькулятор находится в состоянии по умолчанию, AC должно быть показано.
AC должен быть показан в исходном состоянии
Во-первых, если Тим попадает в ключ (любой ключ, кроме четкого), AC следует изменить на CE Отказ
Перемены переменного тока в CE, когда ключ (кроме ясно) получает удар
Мы делаем это, проверив, если Data-Action это чистый . Если это не ясно Мы ищем четкую кнопку и изменить его TextContent Отказ
if (action !== 'clear') {
const clearButton = calculator.querySelector('[data-action=clear]')
clearButton.textContent = 'CE'
}
Во-вторых, если Тим хиты CE Дисплей должен прочитать 0. В то же время CE следует вернуть до AC Таким образом, Тим может сбросить калькулятор к его начальному состоянию. * *
Если CE нажат, AC должен показать
if (action === 'clear') {
display.textContent = 0
key.textContent = 'AC'
calculator.dataset.previousKeyType = 'clear'
}
Третий , если Тим хитов AC Сбросьте калькулятор к его начальному состоянию.
Чтобы сбросить калькулятор к его начальному состоянию, нам нужно очистить все пользовательские атрибуты, которые мы установили.
if (action === 'clear') {
if (key.textContent === 'AC') {
calculator.dataset.firstValue = ''
calculator.dataset.modValue = ''
calculator.dataset.operator = ''
calculator.dataset.previousKeyType = ''
} else {
key.textContent = 'AC'
}
display.textContent = 0
calculator.dataset.previousKeyType = 'clear'
}
Упаковка
Вот и все! Строительство калькулятора трудно, не развевайте себя, если вы не можете построить калькулятор, не делая ошибок.
Для домашней работы запишите все краевые чехлы, упомянутые выше на листе бумаги, затем перейдите к созданию калькулятора снова с нуля. Посмотрите, можете ли вы получить калькулятор вверх. Возьмите свое время, отбрасывайте свои ошибки один за другим, и вы получите калькулятор в конце концов.
Я надеюсь, что вам понравилось эту статью. Если вы сделали, вы захотите проверить Учите JavaScript – Курс, чтобы помочь вам изучить JavaScript один раз и для всех.
На следующем уроке вы научитесь рефакторировать калькулятор с лучшими практиками.
Оригинал: “https://dev.to/zellwk/how-to-build-a-calculatorpart-2-2b6j”