Refactoring Part 2
Unser EventListener sieht im Moment so aus:
calculatorButtonsDiv.addEventListener('click', e => { // ...
// Release operator pressed state const operatorKeys = [...calculatorButtonsDiv.children].filter( button => button.dataset.buttonType === 'operator'; ) operatorKeys.forEach(button => button.classList.remove('is-pressed'));
if (buttonType === 'clear') { // ... } if (buttonType !== 'clear') { // ... } if (buttonType === 'number') { // ... } if (buttonType === 'decimal') { // ... } if (buttonType === 'operator') { // ... } if (buttonType === 'equal') { // ... }
calculator.dataset.previousButtonType = buttonType;});Wir können den EventListener-Code vereinfachen, indem wir jeden “Button”-Teil in eine zugeordnete (dedizierte) Funktion umbrechen:
calculatorButtonsDiv.addEventListener('click', event => { // ... if (buttonType !== 'clear') { // ... }
if (buttonType === 'clear') handleClearkey(); if (buttonType === 'number') handleNumberkeys(); if (buttonType === 'decimal') handleDecimalkey(); if (buttonType === 'operator') handleOperatorkeys(); if (buttonType === 'equal') handleEqualkey();
calculator.dataset.previousButtonType = buttonType;});Wenn wir viele if-Statements haben, wollen wir idealerweise early returns verwenden. Ein early return sagt uns, dass der restliche Code nicht mehr ausgeführt wird. Das macht Code einfacher verständlich.
// Ideal, but doesn't work:calculatorButtonsDiv.addEventListener('click', event => { // ... if (buttonType !== 'clear') { // ... }
if (buttonType === 'clear') return handleClearkey(); if (buttonType === 'number') return handleNumberkeys(); if (buttonType === 'decimal') return handleDecimalkey(); if (buttonType === 'operator') return handleOperatorkeys(); if (buttonType === 'equal') return handleEqualkey();
calculator.dataset.previousButtonType = buttonType;});Das funktioniert nicht, weil wir am Ende jedes EventListeners buttonType dem previousButtonType zuordnen müssen.
In diesen Fällen ist ein switch-Statement perfekt. Mit switch erhalten wir die benötigte Klarheit und können immer noch die letzte Codezeile ausführen:
calculatorButtonsDiv.addEventListener('click', event => { // ...
if (buttonType !== 'clear') { // ... }
switch (buttonType) { case 'clear': handleClearKey(); break; case 'number': handleNumberKeys(); break; case 'decimal': handleDecimalKey(); break; case 'operator': handleOperatorKeys(); break; case 'equal': handleEqualKey(); break; }
calculator.dataset.previousButtonType = buttonType;});Wir können den Code noch knapper schreiben, in dem wir den case, die aufgerufene Funktion und das break in eine Zeile bringen:
switch (buttonType) { case 'clear': handleClearKey(calculator, button); break; case 'number': handleNumberKeys(calculator, button); break; case 'decimal': handleDecimalKey(calculator); break; case 'operator': handleOperatorKeys(calculator, button); break; case 'equal': handleEqualKey(calculator); break;}Function to handle clear key
Section titled “Function to handle clear key”Wir erzeugen diese Funktion, indem wir alles aus dem if (buttonType === 'clear') kopieren.
function handleClearKey() { display.textContent = '0'; button.textContent = 'AC'; if (previousButtonType === 'clear') { delete calculator.dataset.firstValue; delete calculator.dataset.operator; delete calculator.dataset.modifierValue; }}Um die Funktion aufzurufen, benötigen wir calculator und button. Wir können diese beiden Variablen der Funktion übergeben:
function handleClearKey(calculator, button) { const { previousButtonType } = calculator.dataset;
if (buttonType === 'clear') { display.textContent = '0'; button.textContent = 'AC'; if (previousButtonType === 'clear') { delete calculator.dataset.firstValue; delete calculator.dataset.operator; delete calculator.dataset.modifierValue; } }}
calculatorButtonsDiv.addEventListener('click', event => { // ... switch (buttonType) { case 'clear': handleClearKey(calculator, button); break; } // ...})Function to handle number keys
Section titled “Function to handle number keys”Wir erzeugen eine Funktion handleNumberKeys. Dazu kopieren wir wieder alles von `if (buttonType === ‘number’) in diese Funktion.
function handleNumberKeys() { if (displayValue === '0') { display.textContent = key; } else { display.textContent = displayValue + key; }
if (previousButtonType === 'operator') { display.textContent = key; }
if (previousButtonType === 'equal') { resetCalculator(); display.textContent = key; }}Für diese Funktion benötigen wir key, previousButtonType und displayValue.
key bekommen wir aus button.dataset und previousButtonType aus calculator. Wir übergeben also diese beiden Variablen.
function handleNumberKeys(calculator, button) { const { previousButtonType } = calculator.dataset; const { key } = button.dataset; // ...}displayValue erhalten wir aus getDisplayValue:
function handleNumberKeys(calculator, button) { const displayValue = getDisplayValue(); // ...}Verwendung von handleNumberKeys:
calculatorButtonsDiv.addEventListener('click', event => { // ... switch (buttonType) { // ... case 'number': handleNumberKeys(calculator, button); break; } // ...})Function to handle decimal key
Section titled “Function to handle decimal key”Wieder beginnen wir damit, alles aus if (buttonType === 'decimal') in eine neue Funktion handleDecimalKey zu kopieren:
function handleDecimalKey() { if (!displayValue.includes('.')) { display.textContent = displayValue + '.'; }
if (previousButtonType === 'equal') { resetCalculator(); display.textContent = '0'; }
if (previousButtonType === 'operator') { display.textContent = '0.'; }}handleDecimalKey benötigt displayValue und previousButtonType.
displayValueerhalten wir ausgetDisplayValuepreviousButtonTypefinden wir incalculator.dataset
Wir müssen also calculator an die Funktion handleDecimalKey übergeben.
function handleDecimalKey(calculator) { const displayValue = getDisplayValue(); const { previousButtonType } = calculator.dataset;
if (!displayValue.includes('.')) { display.textContent = displayValue + '.'; }
if (previousButtonType === 'equal') { resetCalculator(); display.textContent = '0.'; }
if (previousButtonType === 'operator') { display.textContent = '0.'; }}Verwendung von handleDecimalKey:
calculatorButtonsDiv.addEventListener('click', event => { // ... switch (buttonType) { // ... case 'decimal': handleDecimalKey(calculator); break; } // ...});Function to handle operator keys
Section titled “Function to handle operator keys”Wir kopieren alles aus if (buttonType === 'operator') in eine neue Funktion handleOperatorKeys.
function handleOperatorKeys() { button.classList.add('is-pressed');
const firstValue = calculator.dataset.firstValue; const operator = calculator.dataset.operator; const secondValue = displayValue;
if ( previousButtonType !== 'operator' && previousButtonType !== 'equal' && firstValue && operator ) { const result = calculate(firstValue, operator, secondValue) { display.textContent = result; calculator.dataset.firstValue = result; } else { calculator.dataset.firstValue = displayValue; }
calculator.dataset.operator = button.dataset.key }}In dieser Funktion benötigen wir calculator, button und displayValue.
Wir übergeben calculator und button an die Funktion.
function handleOperatorKeys(calculator, button) { const { previousButtonType, firstValue, operator } = calculator.dataset;
// ...}displayValue erhalten wir aus getDisplayValue:
function handleOperatorKeys(calculator, button) { const displayValue = getDisplayValue(); // ...}Verwendung von handleOperatorKeys:
calculatorButtonsDiv.addEventListener('click', event => { // ... switch (buttonType) { // ... case 'operator': handleOperatorKeys(calculator, button); break; }});Function to handle Equal key
Section titled “Function to handle Equal key”Zuletzt benötigen wir noch eine Funktion für den equal key. Wir kopieren also wieder alles aus if (buttonType === 'equal') in die neue Funktion handleEqualKey.
function handleEqualKey() { const firstValue = calculator.dataset.firstValue; const operator = calculator.dataset.operator; const modifierValue = calculator.dataset.modifierValue; const secondValue = modifierValue || displayValue;
if (firstValue && operator) { const result = calculate(firstValue, operator, secondValue); display.textContent = result; calculator.dataset.firstValue = result; calculator.dataset.modifierValue = secondValue; } else { display.textContent = parseFloat(displayValue) * 1; }}In dieser Funktion benötigen wir calculator und displayValue:
function handleEqualKey(calculator) { const displayValue = getDisplayValue(); const { firstValue, operator, modifierValue } = calculator.dataset;
// ...}Verwendung von handleEqualKey:
calculatorButtonsDiv.addEventListener('click', event => { // ... switch (buttonType) { // ... case 'equal': handleEqualKey(calculator, button); break; }});