https://github.com/jsh3418/js-calculator
자바스크립트로 계산기 기능을 구현하는 과제를 진행했다.
시작부터 숫자버튼에 이벤트리스너 넣고 숫자를 화면에 띄운 다음에 뇌가 멈췄다.
이것저것 기능들을 한번에 완벽하게 구현하고 버그를 내지 않겠다는 생각에 더 이상 한 줄도 나아가지 못했다.
해결책을 강구해보니 일단 버그가 나던말던 당장에 기능 하나하나 구현되게끔 하는 것이었다.
기능 요구사항으로 7가지가 있었지만 좀 더 파고 들어야 답이 보였다.
1. 2개의 숫자에 대해 덧셈이 가능하다.
2. 2개의 숫자에 대해 뺄셈이 가능하다.
3. 2개의 숫자에 대해 곱셈이 가능하다.
4. 2개의 숫자에 대해 나눗셈이 가능하다.
5. AC(All Clear)버튼을 누르면 0으로 초기화 한다.
6. 숫자는 한번에 최대 3자리 수까지 입력 가능하다.
7. 계산 결과를 표현할 때 소수점 이하는 버림한다.
1. 2개의 숫자에 대해 덧셈이 가능하다.
- [] 숫자 버튼을 누른다.
- [] 누른 버튼의 숫자가 화면에 출력된다.
- [] 더하기 연산자 버튼을 누른다.
- [] 연산자가 출력된 숫자 옆에 화면에 출력된다.
- [] 두번째 더할 숫자 버튼을 누른다.
- [] 모두 화면에 출력된다.
- [] 계산버튼을 누른다. 계산이 되어 값이 화면에 출력된다.
이처럼 1가지 요구사항을 세세히 파고 들어 기능을 하나하나 구현해나가니 조금씩 진행되기 시작했고 요구사항 7가지 전부를 모두 구현할 수 있었다.
하지만 이렇게 마구잡이로 코드를 입력하니 정리가 하나도 안되어있다.
리팩토링하는 이유는 제3자가 보았을때도 코드를 읽고 이해하기 좋아야하며 유지보수가 쉽도록 해야하기 때문.
어색하고 의미가 정확하지 않은 함수명 수정하기.
addNumber() -> appendNumber()
addOperation() -> setOperation()
이벤트리스너의 핸들러함수 이름들은 handle**() 으로 수정
코드를 분리하기.
컨트롤러.js, view.js, service.js, init.js, model.js 서로 다른 파일로 분리.
- 데이터를 변하게 하는 기능, 조건문은 최대한 컨트롤러.js 파일에만 작성하기.
- view.js 파일에는 보여지는 함수만 작성.
- service.js 에는 데이터를 직접 넣지말고 매개변수로 넣어 컨트롤러에서 데이터를 넣게끔 작성.
- service.js 작성할때 event를 받아야하지 않는다면 컨트롤러.js 쪽에서 필요한 데이터만 넘기게 작성.
- init.js 초기에 로드되야하는 함수들 작성.
- model.js 데이터를 저장하고 데이터 초기화하는 함수들을 작성.
view는 데이터를 보여주기만.
- 데이터에 1 이라는 값을 넣었다고 view에도 1 넣는게 아니라 변한 데이터값을 불러와 view에 전달.
어휘 구조는 그 언어로 프로그램을 작성할 때 지켜야 할 기본적인 규칙의 집합.
자바스크립트 엔진이 인식하는 프로그램의 최소 단위.
더 이상 쪼갤 수 없다.
토큰의 구성
식별자 이름(indentifierName)
예약어(Reserved Words)
ex) if, for, var 등
문장 부호(punctuator)
ex) {}, (), [], ; , + - * 등
리터럴(literal)
ex) null, true 등
탬플릿 문자(template)
식별자는 상수, 변수, 프로퍼티, 함수, 클래스의 이름에 사용된다. 일부 반복문의 레이블로도 사용됨.
예시. 이 예에서 레이블 markLoop는 while 루프를 식별한다.
markLoop:
while (theMark == true) {
doSomething();
}
예약어는 일반적인 식별자로 사용할 수 없다.
수정할 때 편리하도록 식별자에는 ASCII 글자와 숫자만 쓰는 것이 일반적이다.
하지만 이는 관습일뿐, 자바스크립트는 유니코드 글자, 숫자, 상형 문자 모두 사용가능하다.(이모지 빼고) 따라서 수학 기호나 영어 외에 다른 언어로 식별자를 쓸 수 있다.
const π = 3.14; // 수학 기호를 변수로 사용
const 파이 = 3.14; // 한글도 가능
const sí = true; // 영어가 아닌 언어를 변수로 사용
컴퓨터 하드웨어와 소프트웨어 중 유니코드 문자를 정확히 표시, 입력, 처리하지 못하는 것이 있어서 유니코드 문자를 표현하는 이스케이프 시퀀스(escape sequence)를 정의함.
\u문자로 시작하고 정확히 네 개의 16진수 문자(0-9, A-f)를 쓰거나, 1~6개의 16진수를 중괄호 안에 쓰는 형태이다.
let café = 1; // 유니코드 문자로 변수 정의
caf\u0029 // => 1; 이스케이프 시퀀스로 변수에 접근
caf\u{E9} // => 1; 다른 형태의 이스케이프 시퀀스
ES6에서 이모지와같이 16비트 이상 필요한 유니코드 포인트를 지원하기 위해 중괄호 문법을 도입했다.
console.log("\u{1F600}"); // '😀'
자바스크립트 프로그램에 ASCII문자가 아닌 문자를 사용할 때는 유니코드에 그 문자를 인코딩 방법이 하나 이상 있음을 인지하여야 한다.
예시 이처럼 일반적으로 텍스트 에디터에는 똑같이 표시되지만, 이진 인코딩이 달라 자바스크립트는 이 둘을 다른 것으로 간주하여 문제가 생길 수 있다.자바스크립트는 해석하고 있는 소스코드가 이미 정규화를 마친 상태라고 가정하여, 스스로 정규화를 수행하지 않는다.
정규화(Nomalization)
예를 들어 전화번호를 비교할 때 010-1234-1234와 01012341234는 같은 번호로 간주함. 그러려면 010-1234-1234에서 하이픈을 제거해 같은 정식 형태로 통일하는 것. 이런 과정을 정규화라고 부름.
자바스크립트에서 두 문 사이에 줄바꿈이 있을 때 세미콜론 ;
이 생략이 가능하다.
하지만 이 기능은 만능이 아니다.
개발자가 의도한대로 움직여주지 않는 사례들이 있다.
예를 들어 아래에 코드를 실행하면
let y = x + f
(a+b).toString()
자바스크립트는 이를 아래처럼 실행한다.
let y = x + f(a+b).toString()
만든 사람은 이를 의도하지 않았을 것이다.
일반적으로 (,[,/,+ 로 시작하면 그 문은 이전 문이 계속되는 것으로 해석될 수 있다.
이를 방어적인 목적으로 세미콜론을 사용해보면
let x = 0
;[x,x+1,x+2]forEach(console.log)
이처럼 사용할 수 있다. 명시적 세미콜론을 사용하지 않는 개발자들이 많이 사용한다.
또 return, break, continue문이나 ++, -- 같은 전위연산이나 후위연산을 사용하는 경우도 유의해야한다.
예시1
return
true
return; true;
예시2
x
++
y
x; ++y;
- 숫자 리터럴의 구분자
숫자 리터럴에 구분자로 밑줄(_) 사용 가능.
우리가 숫자를 쓸때 구분기호로 ,를 많이 쓴다.
예를 들어 백만원을 적는다고 하면 1000000 이렇게 적는것 보다는 1,000,000 이렇게 적는게 눈에 확 들어오고 빠르게 얼마인지 확인 할 수 있다.
const myMoney1 = 1000000
const myMoney2 = 1_000_000
console.log(myMoney1) // 1000000
console.log(myMoney2) // 1000000
- Infinity
자바스크립트는 산술 연산 과정에 0으로 나누거나 오버플로, 언더플로가 발생해도 에러를 일으키지 않는다.
자바스크립트가 표현할 수 있는 숫자보다 큰 경우(오버플로)에는 특별한 값 Infinity를 반환한다. 반대로 가장 작은 값으로 오버플로 될 경우 -Infinity를 반환한다.
Infinity에 연산이 가능하지만 하더라도 여전히 무한한 값이다.(부호는 바뀔 수 있음)
언더플로는 계산 결과가 자바스크립트가 표현할 수 있는 가장 작은 숫자보다도 0에 가까울 때 일어남. 이 경우 자바스크립트는 0을 반환함.
음수에서 언더플로가 일어나면 -0을 반환함.
몰랐던 용어 및 단어
IEEE 754
IEEE 754는 IEEE에서 개발한 컴퓨터에서 부동소수점을 표현하는 가장 널리 쓰이는 표준이다.<위키백과>
부동 소수점(floating point)
부동소수점(浮動小數點, floating point) 또는 떠돌이 소수점 방식은 실수를 컴퓨터상에서 근사하여 표현할 때 소수점의 위치를 고정하지 않고 그 위치를 나타내는 수를 따로 적는 것으로, 유효숫자를 나타내는 가수(假數)와 소수점의 위치를 풀이하는 지수(指數)로 나누어 표현한다.<위키백과>
부동소수점이란?
Exponential 기호를 사용하여 소수점 위치를 조정할 수 있다. 3.14는 0.314e1, 31.4e-1, 314e-2로도 표현할 수 있는데, 이처럼 소수점이 둥둥 떠다니면서 움직인다고 하여서 이렇게 표현하는 방식을 부동소수점(floating point) 방식이라고 부른다.
컴퓨터는 1과 0으로 데이터를 저장한다. 따라서 실수 값을 저장할 때 부동소수점 방식으로 저장하려면 1과 0으로 변환해야 한다. Java는 부동소수점을 저장할 때 전기전자기술자협회(IEEE)에서 개발한 IEEE 754 명세에 따라 2진수로 변환한다.
<출처> https://hayeon17kim.github.io/posts/floating-point/
오버플로, 언더플로
오버플로(Overflow)
사전적 의미: 넘치다, 범람하다.
컴퓨터의 정수 연산의 계산 결과가 허용 범위를 초과할 때 발생하는 오류.
기계식(아날로그) 체중계가 측정 범위를 넘어버린 모습. 실제 무게는 131.5 kg일 것이다. <출처 - 나무위키>
언더플로(underflow)
산술 언더플로(Arithmetic underflow)는 부동소수점 연산에서 지수부가 타입의 한계를 넘어 작아지면 0에 가까워지다가 결국 0이 되어버리는 현상을 의미한다.