JavaScript · 2장 기본
함수: 이름 붙인 작업 묶음
같은 계산을 여러 곳에서 하게 되면 코드를 복사하고 싶어져요. 그 대신 작업에 이름을 붙여 묶어 두는 게 함수예요. 함수를 만들고 부르는 법, 값을 넣고 돌려받는 법, 좋은 함수의 크기와 이름을 정리했어요.
01. 함수 만들고 부르기
function 이름(매개변수) { 본문 }으로 함수를 만들고, 이름(인자)로 불러요. 괄호 안에서 받는 이름(price, qty)을 매개변수, 부를 때 실제로 넣는 값(1200, 3)을 인자라고 해요. return 뒤의 값이 함수를 부른 자리로 돌아가요.
function lineTotal(price, qty) {
return price * qty;
}
console.log(lineTotal(1200, 3)); // 3600
const sum = lineTotal(1200, 3) + lineTotal(500, 2);
console.log(sum); // 4600
함수를 만들어 두기만 하면 아무 일도 일어나지 않아요. 불러야 실행돼요. 그리고 같은 함수를 몇 번이든 다른 값으로 부를 수 있어요. 가격 계산 규칙이 바뀌면 함수 한 곳만 고치면 돼요.
02. 매개변수와 기본값
인자를 덜 넣으면 남은 매개변수는 undefined가 돼요. 오류는 나지 않으니 계산이 조용히 NaN이 되기 쉬워요. 그래서 빠질 수 있는 매개변수에는 기본값을 적어 둬요.
function lineTotal(price, qty = 1) {
return price * qty;
}
console.log(lineTotal(1200)); // 1200 — qty가 빠져서 기본값 1
console.log(lineTotal(1200, undefined)); // 1200 — undefined도 기본값을 써요
console.log(lineTotal(1200, null)); // 0 — null은 "값이 있음"이라 기본값을 쓰지 않아요
기본값은 인자가 undefined일 때만 쓰여요. null을 넣으면 그대로 null이 들어가서, 곱셈에서 0으로 바뀌어요. 매개변수가 서너 개를 넘어가면 순서를 헷갈리기 쉬우니, 객체 하나로 받는 방법을 써요(5장 구조 분해에서 다뤄요).
03. return: 결과를 돌려주고 끝내요
return을 만나면 함수는 그 자리에서 끝나고 값을 돌려줘요. return이 없거나 값 없이 return;만 쓰면 undefined를 돌려줘요. 그래서 결과를 화면에 찍기만 하는 함수와, 결과를 돌려주는 함수는 쓰임이 달라요.
function printTotal(price, qty) {
console.log(price * qty); // 찍기만 해요
}
function getTotal(price, qty) {
return price * qty; // 돌려줘요
}
const a = printTotal(500, 2); // 1000이 찍혀요
const b = getTotal(500, 2);
console.log(a, b); // undefined 1000
결과를 돌려주는 함수는 다른 계산에 이어 쓸 수 있고, 테스트하기도 쉬워요(3장). 화면에 찍기 · 저장하기 같은 일은 결과를 받은 쪽에서 하는 게 좋아요.
04. 함수 안의 변수, 바깥의 변수
함수 안에서 만든 변수는 그 함수 안에서만 써요. 함수가 끝나면 사라져요. 반대로 함수는 바깥에 있는 변수를 읽고 바꿀 수도 있어요. 하지만 바깥 변수를 바꾸는 함수는 언제 어디서 값이 바뀌는지 추적하기 어려워져서, 필요한 값은 인자로 받고 결과는 return으로 돌려주는 편이 안전해요.
let visits = 0; // 바깥 변수
function countVisit() {
const now = '오늘'; // 함수 안 변수
visits++; // 바깥 변수를 바꿔요
return `${now} ${visits}번째 방문`;
}
console.log(countVisit()); // 오늘 1번째 방문
console.log(countVisit()); // 오늘 2번째 방문
console.log(typeof now); // undefined — 바깥에서는 보이지 않아요
함수가 바깥 변수를 기억하는 원리는 6장 클로저에서 자세히 봐요.
05. 이름 짓기와 크기
함수 이름은 무엇을 하는지 동사로 시작해요. 이름만 보고 무엇을 돌려주는지 짐작할 수 있으면 좋은 이름이에요.
| 시작 단어 | 예 | 뜻 |
|---|---|---|
| get · calc | getTotal, calcShipping | 값을 계산해서 돌려줘요 |
| is · has · can | isFreeShipping, hasStock | 참 · 거짓을 돌려줘요 |
| create · make | createOrder | 새 값(객체)을 만들어 돌려줘요 |
| show · save · send | showToast, saveCart | 바깥에 영향을 주는 일을 해요 |
함수 하나는 한 가지 일만 하게 해요. 이름에 "그리고"가 들어가야 설명된다면(validateAndSave) 둘로 나눌 때예요. 함수가 한 화면을 넘게 길어져도 나눌 신호예요.
금액을 받아서 50000원 이상이면 true, 아니면 false를 돌려주는 함수 isFreeShipping을 만들어 보세요. 아래 세 줄이 차례로 true, true, false가 나와야 해요.
// 여기에 함수를 만들어 보세요
console.log(isFreeShipping(62000));
console.log(isFreeShipping(50000));
console.log(isFreeShipping(49900));
해답 보기
비교식 자체가 true · false라서 if 없이 바로 돌려주면 돼요.
function isFreeShipping(amount) {
return amount >= 50000;
}
같은 할인 계산이 세 번 복사돼 있어요. 할인율 계산을 함수 하나로 묶어서 세 줄을 그 함수를 부르는 코드로 바꿔 보세요. 결과(9000, 18000, 4500)는 그대로여야 해요.
const shirt = 10000 - 10000 * 0.1;
const pants = 20000 - 20000 * 0.1;
const socks = 5000 - 5000 * 0.1;
console.log(shirt, pants, socks);
해답 보기
할인율도 매개변수로 받고 기본값을 주면, 나중에 할인율이 바뀌거나 상품마다 달라져도 함수 하나로 처리할 수 있어요.
function discounted(price, rate = 0.1) {
return price - price * rate;
}
console.log(discounted(10000), discounted(20000), discounted(5000)); // 9000 18000 4500
06. 실전 포인트
- 언제 쓰나요? 같은 코드가 두세 번 보이면 함수로 묶어요. 한 번만 쓰더라도 이름을 붙이면 읽기 쉬워지는 덩어리(복잡한 조건, 긴 계산)는 함수로 빼요.
- 대신 쓰는 것: 바깥 변수를 바꾸는 대신 인자로 받고
return으로 돌려줘요. 매개변수가 많으면 객체 하나로 받아요. 빠질 수 있는 인자에는 기본값을 써요. - 흔한 실수:
return을 빼먹어서undefined를 받는 것, 인자 순서를 바꿔 넣는 것(lineTotal(qty, price)),null을 넣고 기본값이 쓰이길 기대하는 것이에요.
정리
function 이름(매개변수) { … }로 만들고이름(인자)로 불러요. 부르기 전에는 실행되지 않아요.- 빠진 인자는
undefined예요. 기본값은undefined일 때만 쓰여요. return은 값을 돌려주고 함수를 끝내요. 없으면undefined를 돌려줘요.- 함수 안 변수는 안에서만 보여요. 함수는 한 가지 일만, 이름은 동사로 시작해요.