모던 JavaScript 튜토리얼을 읽고 정리하였습니다.
함수
함수는 프로그램을 구성하는 ‘구성 요소(building block)’로, 이를 이용하면 유사한 동작을 하는 코드를 여러번 호출할 수 있다. 이번 챕터에서는 함수를 직접 만드는 방법에 대해 알아볼 것이다.
함수 선언
함수 선언(function declaration) 방식을 이용하면 함수를 만들 수 있다.
function showMessage() {
alert('안녕하세요!');
}
위 함수에는 매개변수가 없는데, 만약 매개변수가 여러개 있다면 콤마로 구분한다. 이어서 함수를 구성하는 코드의 모임인 함수 본문(body)을 중괄호로 감싸 붙여준다.
function name(parameters) {
...함수 본문...
}
정의한 함수는 다음과 같이 호출하면, 함수 본문이 실행된다.
fuction showMessage() {
alert('안녕하세요!');
}
showMessage();
지역 변수
함수 내에서 선언한 변수인 지역 변수(local varable)는 함수 안에서만 접근 가능하다.
function showMessage() {
let message = "안녕하세요!";
alert(message);
}
showMessage(); // 안녕하세요!
alert(message); // ReferenceError: message is not defined
외부 변수
함수 내부에서 함수 외부의 변수인 외부 변수(outer variable)에 접근할 수 있다.
let userName = 'John';
function showMessage() {
let message = 'Hello, ' + userName;
alert(message);
}
showMessage(); // Hello, John
함수에선 외부 변수에 접근하는 것 뿐만 아니라, 수정도 할 수 있다.
let userName = 'John';
function showMessage() {
userName = 'Bob';
let message = 'Hello, ' + userName;
alert(message);
}
alert(userName); // 함수 호출전, John이 출력됨
showMessage();
alert(userName); // 함수를 호출하여 Bob이 출력됨
함수 내부에 외부 변수와 동일한 이름을 가진 변수가 선언되면 내부 변수는 외부 변수를 가리므로 외부 변수를 사용할 수가 없다.
let userName = 'John';
function showMessage() {
let userName = "Bob";
let message = 'Hello, ' + userName; // Bob
alert(message);
}
showMessage();
alert(userName); // John
전역 변수(global variable)
위 예시의 userName처럼, 함수 외부에 선언된 변수는 전역 변수라고 부른다. 전역 변수는 같은 이름을 가진 지역 변수에 의해 가려지지만 않는다면 모든 함수에서 접근이 가능하다.
변수는 연관되는 함수 내에 선언하고, 전역 변수는 되도록 사용하지 않는 것이 좋다. 비교적 근래에 작성된 코드들은 대부분 전역 변수를 사용하지 않거나 최소한으로 사용한다. 다만 프로젝트 전반에서 사용되는 데이터는 전역 변수에 저장하는 것이 유용한 경우도 있다.
매개변수
매개변수(parameter)를 이용하면 임의의 데이터를 함수 안에 전달할 수 있다. 인수(argument)라고 불리기도하며 엄밀히는 매개변수 안에 지정되는 값을 인수라고 한다.
아래 예시에서 함수 showMessage는 매개변수 from과 text를 가진다. 함수를 호출할 때, 함수에 전달된 인자는 각각 지역변수 from과 text에 복사된다. 그 후 함수는 지역 변수에 복사된 값을 사용한다.
function showMessage(from, text) {
alert(from + ": " + text);
}
showMessage('Ann', 'Hello!'); // Ann: Hello!
showMessage('Ann', "What's up?"); // Ann: What's up?
또 하나의 예시에서는 전역 변수 from이 있고, 이 변수를 함수에 전달한다. 함수가 from을 변경하지만, 변경 사항은 외부 변수 from에 반영되지 않는다. 함수는 언제나 복사된 값만을 사용하기 때문이다.
function showMessage(from, text) {
from = '*' + from + '*';
alert(from + ": " + text);
}
let from = "Ann";
showMessage(from, "Hello"); // *Ann*:Hello
alert(from); // Ann
기본값
매개 변수에 값을 전달하지 않으면 그 값은 undefined가 된다. 위에서 정의한 함수 showMessage(from, text)는 매개변수가 2개이지만, 아래와 같이 인수를 하나만 넣어서 호출해도 에러가 나지 않는다. 두번쨰 매개변수에 값을 전달하지 않았기 때문에, text엔 undefined가 할당된다. 따라서 에러 없이 Ann: undefined가 출력된다.
showMessage("Ann"); // Ann: undefined
매개 변수에 값을 전달하지 않아도 그 값이 undefined가 되지 않게 하려면 기본 값을 설정해주면 된다. 매개변수 오른쪽에 =을 붙이고 undefined 대신 설정하고자 하는 기본값을 써주면 된다.
function showMessage(from, tex="no text given") {
alert(from + ": " + text);
}
showMessage("Ann"); // Ann: no text given
또한 기본 값으로 아래와 같이 복잡한 표현식도 설정 가능하며, 표현식의 결과값이 기본값으로 설정된다.
function showMessage(from, text=anotherFunction()) {
...
}
매개변수 기본값 평가 시점
자바스크립트에선 함수를 호출할 때마다 해당하는 매개변수가 없으면 매번 기본값을 평가한다.
매개변수 기본값을 설정할 수 있는 또 다른 방법
가끔은 함수 선언부에서 매개변수 기본값을 설정하는 대신 함수가 실행되는 도중에 기본값을 설정하는게 논리에 맞는 경우도 생긴다. 이런 경우엔 매개변수를 undefined와 비교하여 매개변수가 생략되었는지를 확인한다.
function showMessage(text) {
if (text === undefined) {
text = '빈 문자열';
}
alert(text);
}
showMessage(); // 빈 문자열
이렇게 if문을 쓰는 것 대신 논리 연산자 | 를 사용할 수도 있다. |
function showMessage(text) {
text = text || '빈 문자열';
...
}
이 외에도 모던 자바스크립트 엔진이 지원하는 null 병합 연산자(nullish coalescing operator) ??를 사용하면 0처럼 falsy로 평가되는 값들을 일반 값처럼 처리할 수 있어서 좋다.
function showCount(count) {
alert(count ?? "unknown")
}
showCount(0); // 0
showCount(null); // unknown
showCount(); // unknown
반환값
함수를 호출했을 때 함수를 호출한 그곳에 특정 값을 반환하게 할 수 있다. 이 때 이 특정 값을 반환 값(return value)라고 부른다.
인수로 받은 두 값을 더해주는 간단한 함수를 만들어 반환 값에 대해 알아보도록 한다.
function sum(a, b) {
return a + b;
}
let result = sum(1, 2);
alert(result); // 3
지시자 return은 함수 내 어디서든 사용할 수 있다. 실행 흐름이 지시자 return을 만나면 함수 실행은 즉시 중단되고, 함수를 호출한 곳에 값을 반환한다. 위 예시에선 반환 값을 result에 할당한다.
아래와 같이 함수 하나에 여러개의 return 문이 올 수도 있다.
function checkAge(age) {
if (age >= 18) {
return true;
} else {
return confirm('보호자의 동의를 받으셨나요?');
}
}
let age = prompt('나이를 알려주세요', 18);
if (checkAge(age)) {
alert('접속 허용');
} else {
alert('접속 차단');
}
함수 본문에 return만 명시하는 경우도 있으며, 이때는 함수가 즉시 종료된다.
function showMovie(age) {
if (!checkAge(age)) {
return;
}
alert("영화 상영");
...
}
위 예시에서 checkAge(age)가 false를 반환하면, if문 밑에 줄은 실행이 안되기 때문에 얼럿창을 보여주지 않는다.
return 문이 없거나 return 지시자만 있는 함수는 undefined를 반환한다.
function doNothing() {} alert(doNothing() === undefined); // true
return 지시자만 있는 경우에도 undefined를 반환한다. return은 return undefined와 동일하게 동작한다.
function doNothing() { return; } alert(doNothing() === undefined); // true
return 과 값 사이에는 줄바꿈을 삽입할 수 없다.
자바스크립트는 return문 끝에 세미콜론을 자동으로 넣기 때문에 이렇게 return문을 작성하면 안된다. 위 코드는 아래 코드처럼 동작한다. 즉, 따라서 반환하고자 했던 표현식을 반환하지 못하고 아무것도 반환하지 않는 것처럼 된다.
return; a + b
의도한 대로 줄바꿈을 넣어 표현식을 반환하려면 다음과 같이 중괄호로 표현식을 묶어야한다.
return ( a + b )
함수 이름 짓기
함수의 이름은 대개 동사이며, 가능한 간결하고 명확해야 한다.
함수가 어떤 동작을 하는지 축약해서 설명하는 동사를 접두어로 붙여 함수 이름을 만드는게 관습이다. 다만 팀내에서 반드시 합의된 접두어만 사용해야 한다. 대표적인 접두어로는 다음과 같은 것들이 있다.
- show - 무언가를 보여주는 함수
- get - 무언가를 반환하는 함수
- calc - 무언가를 계산하는 함수
- create - 무언가를 생성하는 함수
- check - 무언가를 확인하고 불린값을 반환하는 함수
함수는 동작 하나만 담당해야 한다.
함수는 함수 이름에 언급된 동작만을 정확히 수행해야 하며, 그 이외의 동작은 수행해선 안된다. 따라서 한 곳에서 이뤄지는 독립적인 두 개의 동작은 독립된 함수 두 개에서 나눠서 수행할 수 있게 해야 한다.
아주 짧은 이름
정말 빈번히 쓰이는 함수 중에 이름이 아주 짧은 함수가 있다. 예를 들어, jQuery 프레임워크에서 쓰이는 함수 $와 Lodash 라이브러리의 핵심 함수 _가 있다.
함수 == 주석
함수는 간결하고, 한 가지 기능만 수행할 수 있게 만들어야 한다. 함수가 길어지면 함수를 잘게 쪼갤 때가 되었다는 신호로 받아들어야한다. 함수를 간결하게 만들면 테스트와 디버깅이 쉬워지기 때문이다. 또한 함수 그 자체로 주석의 역할까지 하게 된다.
예를 통해 이를 이해해 보자. 아래의 함수 showPrimes(n)은 n까지의 소수를 출력한다.
function showPrimes(n) {
nextPrime: for (let i = 2; i < n; i++) {
for (let j = 2; j < i; j++) {
if (i % j == 0) continue nextPrime;
}
alert(i); // 소수
}
}
두 번째 showPrimes(n)는 소수인지 아닌지 여부를 검증하는 코드를 따로 분리해 isPrime(n)이라는 함수에 넣어 작성했다.
function showPrimes(n) {
for (let i = 2; i < n; i++) {
if (!isPrime(i)) continue;
alert(i);
}
}
function isPrime(n) {
for (let i = 2; i < n; i++) {
if (n % i == 0) return false;
}
return true;
}
첫번째보다 두번째 showPrimes(n)에서 본문 안에서 isPrime이라는 함수명을 통해 해당 함수가 소수 여부를 검증하는 동작을 한다는 것을 쉽게 알 수 있다.이렇게 이름만 보고도 어떤 동작을 하는 지 알 수 있는 코드를 자기 설명적(self-describing) 코드라고 부른다.
Comments