☑️ 계산기 만들기
✅ DOMContentLoaded 이벤트 리스너 등록
웹 페이지가 완전히 로드되었을 때 실행될 함수를 등록
DOMContentLoaded 이벤트는 HTML이 로드 및 파싱된 후 실행
document.addEventListener("DOMContentLoaded", function () {
✅ 변수설정
result : 계산 결과 출력
buttons : 모든 버튼 요소저장
expression : 사용자가 입력한 계산식(수식)을 저장할 변수를 선언하고 초기화
let result = document.getElementById("result");
let buttons = document.querySelectorAll("#calculator input[type='button']");
let expression = "";
✅ 버튼 클릭 이벤트 리스너 추가
모든 버튼(buttons)에 대해 forEach 반복문을 사용하여 클릭 이벤트 리스너를 추가
각 버튼이 클릭될 때 실행되는 익명 함수를 정의
let value : 클릭된 버튼의 값을 가져와 value 변수에 저장
buttons.forEach(button => {
button.addEventListener("click", function () {
let value = this.value;
✅ =(등호) 버튼이 클릭된 경우
마지막 입력이 연산자(+, -, *, /, %)인 경우: 연산자를 제거한 식을 다시 추가하여 연산자가 연속으로 오는 것을 방지
ex) 3-3- = 0
eval() : 결과값을 expression에 저장하여 계속 계산(문자열 → 수식화)
* eval()은 보안상 위험할 수 있으므로, 실제 프로젝트에서는 대체 방법을 고려
예외처리 : Error 처리 + 계산 입력수식 "" (초기화)
if (value === "=") {
try {
if (expression.slice(-1).match(/[\+\-\*/%]/)) {
expression = expression.slice(0, -1); // 마지막 연산자를 제외한 값 추가
}
result.value = eval(expression); // 계산 실행
expression = result.value; // 결과 유지
} catch (e) {
result.value = "Error";
expression = "";
}
}
✅ AC(초기화) 버튼 처리
expression을 비우고, result를 "0"으로 초기화
else if (value === "AC") {
expression = "";
result.value = "0";
}
✅ 연산자로 시작하는 것을 방지
처음 입력이 빈칸, +, -, *, /, % 같은 연산자인 경우 입력을 무시
} else {
if (expression === "" && value.match(/[\+\-\*/%]/)) {
return;
✅ 연산자 연속 입력 방지
slice(-1).match(/[\+\-\*/%]/) : 마지막 저장된 수식
value.match(/[\+\-\*/%]/) : 지금 입력된 수식
ex) 3+4--4 일 경우
} else if (
expression.slice(-1).match(/[\+\-\*/%]/) && value.match(/[\+\-\*/%]/)
✅ (, )의 잘못된 조합 방지
'(' 다음으로 */%<>= 수식이 나올경우 + ')' 다음으로 *0~9 수식이 나올경우
|| expression.slice(-1) === "(" && value.match(/[\*/%,<>=]/)
|| expression.slice(-1) === ")" && value.match(/[0-9]/)
✅ 0으로 시작하는 숫자 입력 방지
1. (^|[\+\-\*/%]) → "0" 앞의 문자 검사
^ : 문자열의 시작을 의미
| : 또는(OR) 연산자 (좌우 둘 중 하나가 해당되면 매칭됨)
[\+\-\*/%] : +, -, *, /, % 중 하나와 매칭됨
대괄호 [] 안의 특수문자는 백슬래시 \를 붙여야 함 (예: \+, \*, \%)
즉, "0" 앞에 있는 문자가 아래 중 하나라면 매칭됨:
- 문자열의 시작 (^)
- 연산자 (+, -, *, /, %)
2. 0$ → "0"이 마지막 문자
0 : 숫자 0과 매칭
$ : 문자열의 끝을 의미
현재 입력한 계산식 상태에서 0 앞이 숫자가 아니고, 지금 입력받은 수식이 순자이면 → 0 생략
ex) (1+2) +(0 앞에 숫자가 아니고) 0 3(0 뒤에 숫자일 경우 0 삭제)
if (expression.match(/(^|[\+\-\*/%])0$/) && value.match(/[0-9]/)) {
expression = expression.slice(0, -1); // 마지막 "0" 제거
}
✅ 입력값 추가 및 결과 출력
사용자가 입력한 값을 expression에 추가하고 화면(result.value)에 출력
expression += value;
result.value = expression;
☑️ 전체코드
document.addEventListener("DOMContentLoaded", function () {
let result = document.getElementById("result");
let buttons = document.querySelectorAll("#calculator input[type='button']");
let expression = "";
buttons.forEach(button => {
button.addEventListener("click", function () {
let value = this.value;
if (value === "=") {
try {
if (expression.slice(-1).match(/[\+\-\*/%]/)) {
expression = expression.slice(0, -1); // 마지막 연산자를 제외한 값 추가
}
result.value = eval(expression); // 계산 실행
expression = result.value; // 결과 유지
} catch (e) {
result.value = "Error";
expression = "";
}
} else if (value === "AC") {
expression = "";
result.value = "0";
} else {
if (expression === "" && value.match(/[\+\-\*/%]/)) {
return; // 연산자로 시작 방지
} else if (
expression.slice(-1).match(/[\+\-\*/%]/) && value.match(/[\+\-\*/%]/) // 연산자 연속 입력 방지
|| expression.slice(-1) === "(" && value.match(/[\*/%,<>=]/) // ( 뒤에는 -, 숫자 가능 (음수 허용)
|| expression.slice(-1) === ")" && value.match(/[0-9]/) // ) 뒤에는 숫자가 바로 올 수 없음
) {
return; // 잘못된 입력 방지
}
// 앞이 "0"이고, 뒤에 숫자가 오는 경우 "0"을 제거
if (expression.match(/(^|[\+\-\*/%])0$/) && value.match(/[0-9]/)) {
expression = expression.slice(0, -1); // 마지막 "0" 제거
}
// 결과 출력
expression += value;
result.value = expression;
}
});
});
});
PS. 생각했던 것 보다 더 많은 변수/예외 상황을 고려하여 코드를 작성 해야하는 작업을 통해 공통범위를 잘 묶어서 처리하고, 오류상황에 대해 생각하는 스펙트럼이 넓어진 것 같다. 여기에서 더 많은 옵션과 변수처리를 할수있을 것 같다.
'JavaScript' 카테고리의 다른 글
| [BCGD] 비전공자 백엔드 개발 도전기 (개인프로젝트) (0) | 2025.03.31 |
|---|---|
| [BCGD] 비전공자 백엔드 개발 도전기 (37) (1) | 2025.03.29 |
| [BCGD] 비전공자 백엔드 개발 도전기 (36) (0) | 2025.03.28 |
| [BCGD] 비전공자 백엔드 개발 도전기 (35) (2) | 2025.03.25 |
| [JavaScript] forEach/each/append/appendChild 총 정리 (0) | 2025.03.23 |
