목차
목적에 맞는 함수 설계
명확한 목적에 맞는 함수를 설계하기 위해 필요한 것은 다음과 같다.
1. 하나의 목적
함수를 작성할 때 하나의 기능을 구현하는 목적만 가져야 한다. 하나의 목적만 가지면 무슨 일을 하는지 알기 쉽고, 작성하기도 수월하다.
2. 적절한 함수 이름
함수 이름은 동사(Verb)로 시작해야 한다. 동사는 행위 단어(Action Words)다. 함수 이름이 동사로 시작하면 기능을 알기 쉽다.
3. 이해를 돕는 주석
함수를 작성할 때 주석(Commands)을 작성하면 기능을 이해하고 사용하기 쉽다. 함수에 주석을 추가할 때는 JSDoc 방식을 사용한다. JSDoc은 JavaScript 소스 코드 파일들에 주해를 달기 위해 사용하는 마크업 언어다. JSDoc은 /**로 시작하고, */로 끝나는 여러 줄 주석이다.
Use JSDoc: Index
Index Getting started Getting started with JSDoc A quick start to documenting JavaScript with JSDoc.Using namepaths with JSDoc A guide to using namepaths with JSDoc.Command-line arguments to JSDoc About command-line arguments to JSDoc.Configuring JSDoc wit
jsdoc.app
주석에 작성할 기능은 최소 다음 세 가지 사항을 문서화해야 한다.
- 함수의 목적: JSDoc을 사용해 어떤 기능을 하는지 설명
- 함수의 매개변수: 함수에서 사용한 매개변수에 대한 정보 제공. 타입(type), 이름(name), 설명(description)을 제공하고, 각 매개변수 앞에는 @param 디렉티브(지시자)를 추가한다.
- 함수의 반환 값: 반환되는 값에 대한 정보 제공. 타입(type)과 설명(description)을 제공하고, @returns 디렉티브를 추가한다.
/**
* 플레이어(배열)에서 마지막 플레이어를 가져오는 기능
* @param {Array} players 플레이어 집합(배열)
* @returns {String} 마지막 플레이어 이름
*/
function getLastPlayer(players) {
return players.at(-1)
}
범위(Scope) 관리
범위(Scope)는 변수가 포함된 환경을 지칭하는 이름이다. 변수에 접근할 수 있으면 해당 변수가 범위 내에 있다고 말한다. 반대로 변수가 접근할 수 없으면 변수가 범위 내에 없다고 말한다.
JavaScript에는 5개의 범위가 있다.
- 글로벌(Global Scope): 함수 또는 중괄호({}) 외부에 선언된 변수. 전체 코드에서 접근 가능
- 함수(Function Scope): 함수 내부에 선언된 변수. 함수 내부에서만 접근 가능
- 블록(Block Scope): 중괄호({}) 내부에서 선언된 let, const 변수. 블록 내에서만 사용
- 렉시컬(Lexical Scope): 변수는 선언된 위치 기준으로 접근 가능. 선언 전에 접근 불가
- 클로저(Closure Scope): 외부 함수의 변수를 내부 함수가 참조하는 현상
중첩된 범위
JavaScript 함수 안에는 다른 함수를 포함할 수 있다. 이렇게 하면 중첩된 범위(Nested Scope)가 생성된다.
- 전역 범위에 선언된 변수는 모든 함수(중첩된 함수 포함)에서 접근할 수 있다.
- 바깥 함수 범위에 선언된 변수는 중첩된 함수 범위에서 접근할 수 있지만, 전역 범위에서는 접근할 수 없다.
- 중첩된 함수 범위에 선언된 변수는 바깥 함수 범위와 전역 범위 모두 접근할 수 없다.
다른 범위의 동일 이름 변수
서로 다른 범위에 존재한다면 동일한 이름의 변수를 사용할 수 있다. JavaScript는 현재 범위에서 가장 가까운 변수를 사용한다.
function logName(name) {
console.log(name)
}
const name = '재진'
logName('하린') // '하린'
범위 양도 불가능
각 함수는 고유 범위를 갖는다. 따라서, 함수에 선언된 변수는 외부 범위의 함수로 이전될 수 없다. 함수 내부에서 다른 함수를 호출해도 다른 함수 범위의 변수에 접근하는 것은 불가능하다.
function 함수() {
const 함수범위변수 = '외부의 다른 함수 범위로 이전될 수 없습니다.'
}
function 다른함수() {
함수()
console.log(함수범위함수) // ReferenceError: 함수범위함수 is not defined
}
범위 관리
범위 관리를 위한 세 가지 규칙은 다음과 같다.
- 전역 변수 사용 자제: 전역 변수는 편하지만, 전역 변수가 너무 많아지면 관리가 어려워진다.
- 변수 범위 제한: 함수 외부의 변수에 의존하는 것은 문제를 발생시킬 수 있는 가능성(Negative Side Effects 부작용)이 있다. 함수 내부에 변수를 선언해 함수 범위를 사용하자.
- 상위 범위로 끌어올리기: 일반적으로는 함수 내부에서 사용되는 변수는 함수 범위를 유지하는 것이 좋지만, 때로는 상위 범위로 변수를 끌어올리는 것이 유용할 수 있다.
상태 변경 줄이기
상태(State)란 프로그램의 특정 시점의 스냅샷이다. 변수를 선언하면 상태가 메모리에 저장된다. 변수의 값을 바꾸면, 상태가 변경된다.
함수 내부 변수도 상태지만, 함수가 종료되면 사라지기 때문에 함수보다는 프로그램의 상태에 주의를 기울여야 한다. DOM, window, 기타 변수들이 상태를 가진다. 상태 변경은 사용자 상호작용, 동작 구현 등 프로그램 작동에 필수적이다. 무분별한 변경은 디버깅을 어렵게 하기 때문에 통제가 필요하다.
상태 변경을 효과적으로 줄이려면 다음의 두 가지 일이 발생하는 것을 방지해야 한다.
- 변수 재할당(Reassignements): var 대신 let과 const 사용
- 뮤테이션(Mutations, 변형): 직접 변형하는 것이 아닌, 복제해서 사용
변수 재할당 피하기
변수 재할당은 let으로 선언된 변수에 다른 값을 다시 할당하는 과정이다. 변수 재할당을 피해야 하는 주요 이유는 코드를 읽고 이해하기 어렵게 만들어 복잡성을 증가시키고, 의도치 않게 함수 외부의 변수(외부 상태)를 변경할 위험이 있다는 것이다.
변수 재할당을 피하기 위해 대신 할 수 있는 것은 다음과 같다.
- 변수를 선언할 때 항상 const 사용 권장(값 변경 불가)
- if ... else 조건문을 사용하는 대신, 삼항 연산자 사용 고려(선언할 때 값 결정)
- 여러 조건문 대신 빠른 반환을 사용하는 함수 작성 후, const에 값 할당
오늘 하루를 돌아보며
자바스크립트의 모범 사례를 오늘까지 배운다고 했는데 학습 자료에 아직 뮤테이션, 객체 뮤테이션 방지, 배열 뮤테이션 방지, 순수 함수 & 부수효과가 남아있어서 어떻게 하지 걱정이 됐다. 그런데 자바스크립트의 모범 사례는 React랑 TypeScript랑 연결되는 내용이어서 넘어가기로 했다. 지금은 내용이 잘 이해되지 않는데 TypeScript랑 React 할 때 다시 다룰 예정이라고 하셔서 안심이 됐다. 나중에 하면서 '아, 그때 그게 이 얘기였구나'하고 알면 된다고 하셨다.
무엇이든 마음이 조급하면 제대로 하기 어렵다. 빠르든 느리든 마음에 여유를 갖고 자기의 페이스에 맞게 하는 게 좋은 것 같다. 남들과 비교하면 조급해진다. 어제의 나와 비교하면서 성장하고 있다는 것을 확인하자! 매일매일 조금씩 성장하는 중이다! 걱정 말자!