앞으로 사용하게 될 코딩 관례에 대해서 설명할 것이다.
디버깅: 스크립트 내 에러를 검출해 제거하는 과정
모던 브라우저에서는 브라우저의 개발자 도구 안에 UI형태로 디버깅 툴을 제공하는데, 이를 사용하면 쉽게 디버깅이 가능하다.여기서는 chrome 브라우저에서 제공하는 디버깅 툴을 사용한다.
F12, macOS: Cmd+Opt+I)Sources탭을 연다.
해당 부분에서 파일 탐색 및 파일의 소스 코드를 확인 가능하다.
개발자 도구 하단부에 이러한 콘솔 창이 있다. 여기에 명령어를 입력하고 Enter를 누르면 입력한 명령어가 실행된다.
테스트를 해보고싶은 간단한 코드의 경우 해당 콘솔에서 테스트 가능하다.

예시페이지의 Sources 탭에서 hello.js스크립트 코드를 확인해본다.

코드가 아닌 줄 번호를 클릭하면 위 처럼 중단점을 추가할 수 있다.
중단점(breakpoint)는 자바스크립트 실행이 중단되는 코드 지점을 지정한다는 뜻이다.
이를 통해 중단된 시점의 변수값, 중단된 시점 기준으로 새로운 명령어 실행 등의 디버깅 작업이 가능해진다.
더 자세한 작업은 Breakpoints 탭에서 핸들링 가능하다.
조건부 중단점(Conditional breakpoint)
줄 번호 오른쪽 클릭으로 조건부 중단점(conditional breakpoint)를 선언할 수도 있다.
조건부 중단점은 변수에 특정 값에 따라 실행을 중단시킬 수 있어 디버깅 시 유용하게 사용 가능하다.
스크립트에 debugger 명령어를 추가해 breakpoint를 설정한 것과 같은 효과를 볼 수 있다.
function hello(name) {
let phrase = `Hello, ${name}!`;
debugger; // <-- 여기서 실행이 멈춥니다.
say(phrase);
}
중단점을 설정했으면 F5(Windows, Linux)나 Cmd+R(macOS)를 통해 새로고침하여 breakpoint를 확인해보자.
중단점을 설정한 곳에서 코드 실행이 멈추게 된다.

이 상태로 하단 탭의 메뉴들을 살펴보자.
Watch: 표현식을 평가하고 결과를 보여준다.
+ 버튼으로 표현식을 입력하면 중단 시점에서의 값을 확인할 수 있다.
입력한 표현식은 실행 도중 계속 재평가된다.

Call Stack: 코드 중단점까지 실행한 경로를 역순으로 보여준다.
index.html > hello 함수 > say 함수 순서대로 호출되었기 때문에 다음과 같은 순서로 Call stack이 나온다.

Scope: 현재 정의된 모든 변수를 보여준다.
Local: 지역 변수를 보여준다.
Global: 전역 변수를 보여준다.
Local하위에 this정보도 있는데, 이는 추후 공부하겠다.
디버깅 영역 상단의 버튼으로 실행 단계마다의 일을 추적하는 방법을 설명한다.

F8)F9)F10)alert같은 내장함수의 경우는 해당하지 않고, 직접 작성한 함수인 경우만 동작이 다르다.)F11)setTimeout같은 비동기 동작을 무시하나, Step into는 비동기 동작을 담당하는 코드를 진입하고, 필요한 경우 비동기 동작이 완료될 때까지 대기한다.Shift+F11)Continue to here 옵션
특정 줄에서 마우스 우클릭으로 "Continue to here"옵션을 확인할 수 있다.
그냥 해당 줄까지 그대로 실행하는 옵션으로, breakpoint를 따로 설정하기 귀찮을 때 유용하게 사용할 수 있다.
console.log 함수를 통해 원하는 값을 콘솔에 출력할 수 있다.
// 콘솔창을 열어 결과를 확인해 보세요.
for (let i = 0; i < 5; i++) {
console.log("숫자", i);
}
위와 같이 콘솔을 사용할 수 있다.
개발자는 가능한 간결하고 읽기 쉽게 코드를 작성해야 한다.
좋은 코드 스타일은 이를 도와준다.
아래 대부분의 내용들이 prettier + eslint 조합으로 신경쓰지 않고 코딩이 가능하다. 이러한 규칙이 있다는 점만 알고 실제로 적용할 때는 auto formatting으로 코드 포맷을 맞추면 될 것이다.

이러한 규칙들이 있는데 위 상세 규칙들이 생긴 이유를 소개한다.
무조건 따라야 하는 규칙은 없다.
스타일에 따라서, 선호하는 방식에 따라서 규칙을 따를 수도 있고, 따르지 않을 수도 있다.
대부분 javascript 프로젝트에서 중괄호는 '이집션(Egyptian)'스타일로 키워드와 같은 줄에 작성한다.
여는 중괄호 앞에 공백이 하나 필요하다.
if (condition) {
// 코드 1
// 코드 2
// ...코드 n...
}
만약 한 줄짜리 구문은 어떻게 다뤄야 할까?
if (n < 0) alert(`Power ${n} is not supported`);
이렇게 한 줄로 사용하는 것도 나쁘지 않고
if (n < 0) {
alert(`Power ${n} is not supported`);
}
이런식으로 사용하는 방법이 가독성이 좋아 가장 추천된다.
가로로 코드가 길어지면 여러 줄로 나누어 작성해야 한다.
백틱을 통해서 문자열을 여러 줄로 나눌 수 있다.
// 백틱(`)을 사용하면 문자열을 여러 줄로 쉽게 나눌 수 있습니다.
let str = `
ECMA International's TC39 is a group of JavaScript developers,
implementers, academics, and more, collaborating with the community
to maintain and evolve the definition of JavaScript.
`;
if문은 다음과 같이 나눌 수 있다.
if (
id === 123 &&
moonPhase === 'Waning Gibbous' &&
zodiacSign === 'Libra'
) {
letTheSorceryBegin();
}
최대 가로 길이는 대게 80~120자로 제한하는게 일반적이다.
show(parameters,
aligned, // 스페이스 다섯 개를 이용해 들여쓰기 함
one,
after,
another
) {
// ...
}
function pow(x, n) {
let result = 1;
// <--
for (let i = 0; i < n; i++) {
result *= x;
}
// <--
return result;
}
javascript 엔진에 의해 자동으로 구문 끝에 세미콜론을 넣어주지만, 예외 상황도 있으므로 항상 세미콜론을 직접 넣어주는게 좋다.
가능한 깊은 중첩문은 사용하지 않도록 한다.
제외되는 상황은 early return하는 방식이나 continue 지시자를 통해서 중첩 레벨을 줄이는게 좋다.
for (let i = 0; i < 10; i++) {
if (!cond) continue;
... // <- 추가 중첩 레벨이 추가되지 않습니다.
}
'헬퍼'함수 여러 개를 만들어 사용하는 경우 다음과 같은 방법으로 코드 구조를 정리할 수 있다.
// 함수 선언
function createElement() {
...
}
function setHandler(elem) {
...
}
function walkAround() {
...
}
// 헬퍼 함수를 사용하는 코드
let elem = createElement();
setHandler(elem);
walkAround();
// 헬퍼 함수를 사용하는 코드
let elem = createElement();
setHandler(elem);
walkAround();
// --- 헬퍼 함수 ---
function createElement() {
...
}
function setHandler(elem) {
...
}
function walkAround() {
...
}
대게 2번째 방법으로 정돈하는 것을 선호한다.
헬퍼 함수 이름을 잘 명명해 함수 역할을 쉽게 유추할 수 있는 상황이면, 함수 본문을 읽을 필요도 없이 코드를 읽어갈 수 있다.
코딩 스타일 가이드는 코드를 어떻게 작성할지에 대한 전반적인 규칙을 담은 문서다.
유명한 스타일 가이드 예시이다.
Linter를 사용하면 내가 작성한 코드가 스타일 가이드에 맞는지 자동으로 확인해준다.
스타일 체크 뿐만 아니라, 변수나 함수의 이름의 오타도 미리 발견할 수 있어 linter 사용을 권장한다.
유명 linter:
주석은 코드가 어떻게 혹은 왜 동작하는지에 대한 설명을 추가하는데 쓰인다.
한 줄 짜리 주석은 //로, 여러 줄 짜리 주석은 /* ... */로 쓴다.
'코드에서 무슨 일이 일어나는지'에 대한 주석이 많아서는 안된다.
기본적으로 주석 없이 코드 자체만으로도 코드가 무슨 일을 하는지 쉽게 이해할 수 있어야한다.
코드가 불분명해서 주석 작성이 꼭 필요한 상태라면, 이는 코드를 다시 작성해야 한다는 뜻일 수 있다.
javascript 기본의 함수파트에서 소수 구하는 함수 내부의 로직을 새로운 함수로 분리해 가독성을 높였다.
함수 이름 자체가 주석 역할을 하므로 코드를 쉽게 이해할 수 있다. 이런 코드를 자기 설명적인(self-descriptive) 코드라고 부른다.
다음처럼 코드가 늘어져있는 경우 새로운 함수를 만들고 코드 일부를 새로 만든 함수에 옮기는게 좋다.
before:
// 위스키를 더해줌
for(let i = 0; i < 10; i++) {
let drop = getWhiskey();
smell(drop);
add(drop, glass);
}
// 주스를 더해줌
for(let t = 0; t < 3; t++) {
let tomato = getTomato();
examine(tomato);
let juice = press(tomato);
add(juice, glass);
}
// ...
after:
addWhiskey(glass);
addJuice(glass);
function addWhiskey(container) {
for(let i = 0; i < 10; i++) {
let drop = getWhiskey();
//...
}
}
function addJuice(container) {
for(let t = 0; t < 3; t++) {
let tomato = getTomato();
//...
}
}
함수는 주석이 없어도 존재 이유를 설명할 수 있어야 한다.
그러나 실무에서 '설명이 담긴'주석을 불가피하게 작성해야 하는 경우도 있는데, 알고리즘이 복잡하거나 최적화를 위해 코드를 비틀어 작성하는 경우에는 설명을 작성해주는게 좋다.
이런 경우를 제외하고는 코드 자체만으로도 이해할 수 있어야 한다.
고차원 수준의 컴포넌트 개요, 컴포넌트 간 상호작용, 상황에 따른 제어 흐름 등은 주석에 넣어주는 것이 좋다. 고차원 수준의 아키텍쳐 다이어그램을 그리는데 쓰이는 언어 UML도 공부해보는걸 추천한다.
JSDoc이라는 문법으로 함수에 관한 문서를 쉽게 쓸 수 있다. 함수의 용례, 매개변수, 반환 값 정보가 들어간다.
ex)
/**
* x를 n번 곱한 수를 반환함
*
* @param {number} x 거듭제곱할 숫자
* @param {number} n 곱할 횟수, 반드시 자연수여야 함
* @return {number} x의 n 거듭제곱을 반환함
*/
function pow(x, n) {
...
}
이렇게 주석을 달면 함수의 목적, 사용법을 한 번에 알 수 있다.
문제 해결 방법은 여러 가지 인데 왜 하필 이 방법을 선택했는지 의문이 들 때가 있다.
나중에 코드를 보며 더 올바른 방법이라고 수정한게, 이전에 시도했는데 먹히지 않았던 방법일 수가 있다.
이전의 실수를 방지하는 안내판 역할을 하는 주석이여서 유용하다.
직관적인 부분과 다른 미묘한 동작을 하는 코드가 있다면 주석을 달아주는 것이 좋다.