JS 파트 1) 2.15 : 함수

함수

스크립트를 작성하다보면 유사한 동작을 하는 코드가 여러 곳에서 필요할 때가 많다. (ex. 로그인/로그아웃 시 안내 메시지 출력)

함수는 프로그램을 구성하는 주요 '구성 요소(building block)'이다. 함수를 이용하면 중복 없이 유사한 동작을 하는 코드를 여러 번 호출할 수 있다.

이번 챕터에서는 함수를 직접 만드는 방법에 대해 알아보겠다.

함수 선언

함수 선언 방식은 아래와 같다.
function 키워드, 함수 이름, 괄호로 둘러싼 매개변수를 차례로 써주면 함수를 선언할 수 있다. 위 함수에는 매개 변수가 없는데, 만약 매개변수가 여러 개 있다면 각 매개변수를 콤마(,)로 구분해준다. 이어서 함수를 구성하는 코드의 모임인 '함수 본문(body)'를 중괄호로 감싸준다.

새롭게 정의한 함수는 함수 이름 옆에 괄호를 붙여 호출할 수 있다.

이렇게 함수를 호출하면 함수 본문이 실행된다. 위처럼 유사 동작을 하는 코드를 중복 없이 여러 번 호출할 수 있게 하는 것이 함수의 주요 용도 중 하나이다(중복 코드 피하기).

지역 변수

함수 내에서 선언한 변수인 지역변수(local variable)는 함수 안에서만 접근할 수 있다.

외부 변수

함수 내부에서 함수 외부의 변수인 외부 변수(outer variable)에 접근하는 것뿐만 아니라, 수정도 할 수 있다.

💡 외부 변수는 지역 변수가 없는 경우에만 사용 가능하다!

함수 내부에 외부 변수와 동일한 이름을 가진 변수가 선언되었다면, 내부 변수는 외부 변수를 가린다.

💡 전역 변수

함수 외부에 선언된 변수는 전역 변수(global variable)라고 부른다. 전역 변수는 같은 이름을 가진 지역 변수에 의해 가려지지만 않는다면 모든 함수에서 접근할 수 있다.

주의❗) 변수는 연관되는 함수 내에 선언하고, 전역 변수는 되도록 사용하지 않는 것이 좋다.

비교적 근래에 작성된 코드들은 대부분 전역변수를 사용하지 않거나 최소한으로만 사용한다. 다만 프로젝트 전반에서 사용되는 데이터는 전역 변수에 저장하는 것이 유용한 경우도 있으니 이 점을 알아두자.

매개변수

매개변수를 이용하면 임의의 데이터를 함수 안에 전달할 수 있다. 매개변수는 인수(argument)라고 불리기도 한다(매개변수와 인수는 엄밀히 같진 않지만, 대개 같다고 본다).

아래 예시에서 함수 showMessage는 매개변수 from과 text를 가진다.
5,6번째 줄에서 함수를 호출하면, 함수에 전달된 인자는 지역변수 from과 text에 복사된다. 그 후 함수는 지역변수에 복사된 값을 사용한다.

예시 하나를 더 살펴보자.
전역 변수 from이 있고, 이 변수를 함수에 전달하였다. 함수가 from을 변경하지만, 변경 사항은 외부 변수 from에 반영되지 않는다. 함수는 언제나 복사된 값을 사용하기 때문이다.

기본값

매개변수에 값을 전달하지 않으면 에러가 발생하지는 않고, 그 값은 undefined가 된다.

매개변수에 값을 전달하지 않아도 그 값이 undefined가 되지 않게 하려면, '기본값(default value)'을 설정해주면 된다. 매개변수 오른쪽에 =을 붙이고 undefined 대신 설정하고자 하는 기본값을 써주면 된다.
EX.
이젠 text가 값을 전달받지 못해도 undefined 대신 기본값 "no text given"이 할당된다.

위 예시에서는 문자열 "no text given"을 기본값으로 설정했다. 하지만 아래와 같이 복잡한 표현식도 기본값으로 설정할 수 있다.

💡 매개변수 기본값 평가 시점

자바스크릅트에서는 함수를 호출할 때마다 매개변수 기본값을 평가한다. 물론 해당하는 매개변수가 없을 때만 기본값을 평가한다.

매개변수 기본값을 설정할 수 있는 또 다른 방법

가끔은 함수 선언부에서 매개변수 기본값을 설정하는 것 대신 함수가 실행되는 도중에 기본값을 설정하는 게 논리에 맞는 경우가 생기기도 한다.

이런 경우엔 일단 매개변수를 undefined와 비교하여 함수 호출 시 매개변수가 생략되었는지를 확인한다. 이렇게 if문을 쓰는 것 대신 논리 연산자 ||를 사용할 수도 있다.이 외에도 모던 자바스크립트 엔진이 지원하는 null 병합 연산자(nullish coalescing operator) ??를 사용하면 0처럼 falsy로 평가되는 값들을 일반 값처럼 처리할 수 있어서 좋다.

반환값

함수를 호출했을 때 함수를 호출한 그곳에 특정 값을 반환하게 할 수 있다. 이때 이 특정 값을 반환 값(return value)이라고 부른다.

인수로 받은 두 값을 더해주는 간단한 함수를 만들어 반환 값에 대해 알아보도록 하겠다.
지시자 return은 함수 내 어디서든 사용할 수 있다. 실행 흐름이 지시자 return을 만나면 함수 실행은 즉시 중단되고 함수를 호출한 곳에 값을 반환한다. 위 예시에선 반환 값을 result에 할당하였다.

아래와 같이 함수 하나에 여러 개의 return문이 올 수도 있다.
아래와 같이 지시자 return만 명시하는 것도 가능하다. 이런 경우 함수가 즉시 종료된다.

💡 return문이 없거나 return 지시자만 있는 함수는 undefined를 반환한다.

❗) return과 값 사이에 절대 줄을 삽입하지 마라.

자바스크립트는 return문 끝에 세미콜론을 자동으로 넣기 때문에 이렇게 작성하면 이렇게 작동한다.
따라서 반환하고자 했던 표현식을 반환하지 못하고 아무것도 반환하지 않는 것처럼 되어버린다.

표현식을 여러 줄에 걸쳐서 작성하고 싶다면,

표현식이 return 지시자가 있는 줄에서 시작하도록 작성해야한다. 또는, 아래와 같이 여는 괄호를 return 지시자와 같은 줄에 써줘도 괜찮다.

함수 이름짓기

  • 함수는 어떤 동작을 수행하기 위한 코드를 모아놓은 것이다. 따라서 함수의 이름은 대개 동사다.
  • 함수 이름은 가능한 한 간결하고 명확해야 합니다.
    - 함수가 어떤 동작을 하는지 설명할 수 있어야 한다. 코드를 읽는 사람은 함수 이름만 보고도 함수가 어떤 기능을 하는지 힌트를 얻을 수 있어야 한다.

함수가 어떤 동작을 하는지 축약해서 설명해주는 동사를 접두어로 붙여 함수 이름을 만드는 게 관습이다. 다만, 팀 내에서 그 뜻이 반드시 합의된 접두어만 사용해야 한다. (ex. "show"로 시작하는 함수는 대개 무언가를 보여주는 함수이다.)

  • "get" : 값을 반환
  • "calc" : 무언가를 계산함
  • "create" : 무언가를 생성함
  • "check" : 무언가를 확인하고 불린값을 반환함
  • 등등...

접두어를 적절히 활용하면 함수 이름만 보고도 함수가 어떤 동작을 하고 어떤 값을 반환하는지 쉽게 알 수 있다.

💡 함수는 동작 하나만 담당해야 한다.

함수는 함수 이름에 언급되어 있는 동작을 정확히 수행해야 한다. 그 이외의 동작은 수행해선 안 된다.
독립적인 두 개의 동작은 독립된 함수 두 개에서 나눠서 수행할 수 있게 해야한다. 한 장소에서 두 동작을 동시에 필요로 한다면, 제3의 함수를 만들어 그곳에서 두 함수를 호출한다.

개발자들이 빈번히 하는 실수

  • getAge 함수는 나이를 얻어오는 동작만 수행해야 합니다. alert 창에 나이를 출력해주는 동작은 이 함수에 들어가지 않는 것이 좋습니다.
  • createForm 함수는 form을 만들고 이를 반환하는 동작만 해야 합니다. form을 문서에 추가하는 동작이 해당 함수에 들어가 있으면 좋지 않습니다.
  • checkPermission 함수는 승인 여부를 확인하고 그 결과를 반환하는 동작만 해야 합니다. 승인 여부를 보여주는 메시지를 띄우는 동작이 들어가 있으면 좋지 않습니다.
    접두어를 붙여 만든 모두 함수는 팀에서 만든 규칙을 반드시 따라야 한다. 팀원들은 이 규칙을 충분히 이해하고 있어야 하며, 팀원들 사이에 이 규칙이 잘 공유되어야 한다.

💡 아주 짧은 이름

정말 빈번히 쓰이는 함수 중에 이름이 아주 짧은 함수가 있다.
⇛ jQuery 프레임워크에서 쓰이는 함수 $와 Lodash 라이브러리의 핵심 함수 _
이 함수들은 지금까지 소개한 함수 이름짓기에 관련된 규칙을 지키지 않고 있다. 예외에 속하는 함수들이다. 다른 대부분의 함수 이름은 간결하고 함수가 어떤 일을 하는지 설명할 수 있게 지어야 한다.

함수 == 주석

함수를 간결하게 만들면 테스트와 디버깅이 쉬워진다. 그리고 함수 그 자체로 주석의 역할까지 한다.

같은 동작을 하는 함수, showPrimes(n)을 두 개 만들어 비교해보자. showPrimes(n)은 n까지의 소수를 출력해준다.

첫 번째 showPrimes(n)

두 번째 showPrimes(n)

두 번째가 더 이해하기 쉬워보인다. isPrime 함수 이름을 보고 해당 함수가 소수 여부를 검증하는 동작을 한다는 걸 쉽게 알 수 있다. 이렇게 이름만 보고도 어떤 동작을 하는지 알 수 있는 코드를 자기 설명적(self-describing) 코드라 부른다.

위와 같이 함수는 중복을 없애려는 용도 외에도 사용할 수 있다. 이렇게 함수를 활용하면 코드가 정돈되고 가독성이 높아진다.

💻 과제

1. else는 정말 필요한가?


📌 답: 기존 코드와 동일하게 작동한다.

2. '?'나 '||'를 사용하여 함수 다시 작성하기


📌 답 - 1. 물음표 연산자 ?를 사용

function checkAge(age) {
	return age > 18 ? true : confirm('보호자의 동의를 받으셨나요?');
}

📌 답 - 2. OR 연산자 ||를 사용

function checkAge(age) {
	return (age > 18) || confirm('보호자의 동의를 받으셨나요?');
}

3. min(a,b) 함수 만들기


📌 답

function min(a, b) {
	return a < b ? a : b;
}

4. pow(x,n) 함수 만들기

📌 답

function pow(x, n) {
	let result = 1;
	for(let i=0 ; i<n ; i++)
    	result *= x;
    return result;
}

let x = prompt('Enter x', '');
let n = prompt('Enter n', '');
if(n < 1) {
	alert('자연수를 입력하세요');
} else {
	alert(pow(+x, +n));
}

이 글은 https://ko.javascript.info/ 를 참고하여 작성하였습니다.

좋은 웹페이지 즐겨찾기