목차11개 항목
출처와 참고
김성현(Witch-Work)의 글 「JS 탐구생활 - JS의 주석은 //과 /* */뿐만이 아니다」(2024.01)를 요약·재구성하고, 좋은 주석을 쓰는 법은 javascript.info(모던 JavaScript 튜토리얼)의 「주석」, 「코드 구조」 글로 보강한 노트다.
주석에 쓸 것과 쓰지 않을 것
주석은 코드가 말할 수 없는 것을 적는다. 코드는 "무엇을 어떻게"를 이미 말한다. 그것을 다시 풀어 쓴 설명 주석이 많다면 코드가 불분명하다는 신호다. 주석이 필요할 만큼 헷갈리는 코드는 먼저 다시 쓴다.
| 쓰지 않는다 | 쓴다 |
|---|---|
코드가 하는 일을 한 줄씩 옮긴 설명(// i가 소수인지 확인) | 전체 구조의 조감도: 모듈·컴포넌트가 어떻게 맞물리는지, 상황별 제어 흐름 |
| 누가 언제 고쳤는지(버전 관리가 맡는다) | 왜 이 방법을 골랐는지. 더 단순해 보이는 방법이 왜 안 되는지 |
| 지운 코드를 주석 처리해 남겨 두기 | 직관에 어긋나는 동작, 일부러 비틀어 쓴 최적화, 외부 버그 우회 |
| 함수의 용도·매개변수·반환값(JSDoc) |
"왜"가 빠진 코드는 나중에 누군가(대개 미래의 자신)가 "그때는 몰랐지" 하며 더 깔끔한 방법으로 고쳤다가, 이미 시도해서 실패했던 이유를 다시 겪는다. 그 이유를 적은 한 줄이 시간을 아낀다.
설명 주석 대신 함수로
주석이 코드 덩어리의 제목 노릇을 하고 있다면, 그 덩어리를 이름 있는 함수로 뽑는다. 함수 이름이 주석을 대신한다(자기 설명적 코드).
// Before: 주석이 블록의 역할을 설명한다
for (let i = 2; i < n; i++) {
// i가 소수인지 확인
// ...중첩 반복문...
}
// After: 이름이 설명한다
for (let i = 2; i < n; i++) {
if (!isPrime(i)) continue
console.log(i)
}// 위스키를 더한다, // 주스를 더한다처럼 주석으로 나뉜 긴 흐름도 addWhiskey(glass), addJuice(glass)로 쪼개면 각 함수가 무엇을 받고 돌려주는지까지 분명해진다. 함수를 얼마나 잘게 나눌지의 원칙은 클린 코드: 함수와 이름에 있다.
JSDoc
함수 위의 /** … */ 블록은 JSDoc 형식으로 쓰면 에디터가 자동완성·툴팁·타입 검사에 쓰고, 문서 생성 도구가 HTML 문서로 만든다.
/**
* x를 n번 곱한 값을 돌려준다.
*
* @param {number} x 거듭제곱할 수
* @param {number} n 곱할 횟수. 자연수여야 한다
* @returns {number} x의 n제곱
*/
function pow(x, n) {}TypeScript 프로젝트에서는 타입을 코드가 맡으므로 {number} 같은 타입 표기는 빼고 설명과 @example·@deprecated·@throws만 남긴다. JS 파일에서도 // @ts-check와 JSDoc 타입으로 TypeScript의 검사를 받을 수 있다. 팀 규칙은 TypeScript 코딩 컨벤션의 「주석과 모듈」에 있다.
그 밖의 요령
- 주석 때문에 코드가 길어지는 것은 걱정하지 않는다. 배포용 빌드의 압축 도구(minifier)가 주석을 지운다. 라이선스 주석(
/*! … */,@license)은 남기도록 설정할 수 있다. - 에디터 단축키(VS Code는
Ctrl+/·Cmd+/)로 줄 주석을 켜고 끈다. // TODO:,// FIXME:는 린터 규칙이나 이슈 트래커와 연결해 두지 않으면 영원히 남는다.
명세의 주석 네 가지: 한눈에 보기
| 주석 | 형태 | 쓸 수 있는 곳 | 생긴 이유 |
|---|---|---|---|
| 한 줄 주석 | // … | 어디서나 | 기본 |
| 여러 줄 주석 | /* … */ | 어디서나 (중첩 불가) | PL/I에서 이어받음 |
| 해시뱅 주석 | #!… | 파일 맨 첫 줄, 앞에 공백 없이 | 실행할 인터프리터 지정 |
| HTML 유사 주석 | <!--, --> | 명세 부록 B. 모듈 코드에서는 쓸 수 없다 | 옛 브라우저 호환 |
실제 코드에서는 //와 /* */만 쓰면 된다. 나머지 둘은 특수한 목적으로 남아 있는 형식이다.
1. 한 줄 주석 //
//부터 줄 끝까지가 주석이다. 토큰은 가능한 한 길게 읽는다는 규칙 때문에 항상 줄 끝까지 이어진다. 줄을 끝내는 문자(LineTerminator)는 네 가지다.
| 이름 | 코드 포인트 |
|---|---|
| LF (Line Feed) | U+000A |
| CR (Carriage Return) | U+000D |
| LS (Line Separator) | U+2028 |
| PS (Paragraph Separator) | U+2029 |
한 줄 주석은 공백처럼 취급된다. 끝의 줄바꿈 문자는 주석에 포함되지 않고 따로 인식되므로, 한 줄 주석은 자동 세미콜론 삽입(ASI)에 영향을 주지 않는다.
2. 여러 줄 주석 /* */
/*로 시작해 처음 나오는 */에서 끝난다. 중첩할 수 없다.
| 경우 | 파싱할 때 취급 |
|---|---|
한 줄 안에 있는 /* */ | 공백 |
줄바꿈을 포함한 /* */ | 주석 전체를 줄바꿈 하나로 본다 (ASI에 영향을 줄 수 있다) |
이 형식은 C보다 먼저 1964년 IBM의 PL/I에서 나왔다. PL/I에서는 문자열 밖에서 /*, */ 조합이 거의 나오지 않았지만, JavaScript는 정규 표현식에서 이 조합이 나올 수 있다. 더글라스 크록퍼드가 든 예는 구문 오류가 난다.
/*
var rm_a = /a*/.match(s);
*/
// 정규식 안의 */에서 주석이 끝나 버린다그래서 주석 처리에는 //가 권장되는 경우가 많다.
3. 해시뱅 주석 #!
#!/usr/bin/env node
console.log('Hello world')- 유닉스에서 파일 첫 줄의
#!뒤 문자열은 그 파일을 실행할 인터프리터를 뜻한다. JavaScript에서도 같은 목적이다. - 스크립트나 모듈의 맨 처음에서만 유효하고,
#!앞에 공백도 있으면 안 된다. - 셸에서 실행하지 않으면 평범한 한 줄 주석과 같다.
- Node.js 같은 브라우저 밖 환경에서 먼저 사실상 표준으로 쓰이다가 명세에 들어왔다. CLI 도구의 실행 파일 첫 줄에서 흔히 본다.
일반 주석 용도로 쓰지 않는다.
4. HTML 유사 주석 <!--, -->
명세의 부록 B.1(Additional Syntax)에 있다.
| 토큰 | 동작 |
|---|---|
<!-- | 한 줄 주석처럼 그 뒤 줄 끝까지 주석 |
--> | 그 뒤 줄 끝까지 주석. 단 줄의 시작(앞에 공백이나 한 줄짜리 /* */만 허용)에 와야 한다 |
console.log(1); <!-- 주석
--> 주석
console.log(1); --> 이건 주석이 아니다 (앞에 코드가 있음)왜 생겼나
JavaScript는 1995년 넷스케이프 내비게이터 2에서 처음 나왔다. 그보다 먼저 나온 모자이크 같은 브라우저는 <script>를 몰라서 스크립트 본문을 페이지에 그대로 글자로 보여 줬다. 그래서 본문을 HTML 주석으로 감쌌다.
<script>
<!-- 옛 브라우저에는 HTML 주석, JS에는 한 줄 주석
alert('this is a message from JavaScript')
// -->
</script>그런데 <!--는 JavaScript 문법이 아니라서 JS를 지원하는 브라우저가 파싱에 실패했다. JavaScript 1.0은 <!--를 한 줄 주석 시작으로 인정했고, --> 앞에는 //를 붙이면 됐다. 이 관행이 오래 쓰이다 보니 결국 표준이 됐다.
정리
- 주석에는 코드가 말할 수 없는 "왜"를 쓴다. 블록을 설명하는 주석은 함수 이름으로 바꾼다. 함수 계약은 JSDoc으로.
- 주석은
//와/* */만 쓴다./* */는 중첩이 안 되고 정규식 속*/에 걸릴 수 있다. - 주석은 공백처럼 취급되지만, 줄바꿈을 품은
/* */는 줄바꿈으로 취급된다. #!는 실행 파일 첫 줄에서 인터프리터를 지정할 때만 쓴다.<!--/-->는 1990년대 브라우저 호환의 흔적이다. 언어의 역사가 명세에 남은 예다.
관련 노트: 클린 코드: 함수와 이름, TypeScript 코딩 컨벤션, 문(Statement)과 식(Expression), 변수와 데이터 타입, JavaScript는 인터프리터 언어일까, 컴파일 언어일까, 프론트엔드의 등장 배경