Study/JavaScript

JavaScript [함수]

maino77 2021. 8. 20. 21:21

스크립트를 작성하다 보면 유사한 동작을 하는 코드가 여러 곳에서 필요한 경우가 있습니다.

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

앞서 우리는 alert, prompt, confirm 과 같은 내장 함수를 배웠습니다. 이번에는 함수를 직접 만드는 방법에 대해 알아보겠습니다.

 

 

함수 선언

함수 선언 방식을 이용하면 함수를 만들 수 있습니다. (함수 선언 방식은 함수 선언문이라 부르기도 합니다.)

함수 선언 방식은 아래와 같이 작성할 수 있습니다.

function showMessage() {
	alert('안녕하세요');
    }

function 키워드, 함수 이름, 괄호로 둘러싼 매개변수를 차례로 쓰면 함수를 선언할 수 있습니다.

위의 예시에는 매개변수가 없느데, 만약 매개변수가 여러 개 있다면 각 매개변수를 콤마로 구분해줍니다.

이어서 함수를 구성하는 코드의 모임인 '함수 본문(body)'를 중괄호로 감싸줍니다.

function name(parameters) {
  ...함수 본문...
}

 

새롭게 정의한 함수는 함수 이름 옆에 괄호를 붙여 호출할 수 있습니다. name() 과 같이 가능합니다.

function name(){
 let yourName = prompt('What you`re name?', '');
 
 alert(yourName);
 }
 
 name();

 

 

지역 변수

함수 내에서 선언한 변수인 지역 변수는 함수 안에서만 접근할 수 있습니다.

function name(){
 let yourName = prompt('What you`re name?', '');
 
 alert(yourName);
 }
 
 name();
 
 yourName(); // 에러가 발생합니다.

 

 

외부 변수

함수 내부에서 함수 외부의 변수인 외부 변수에 접근할 수 있습니다.

let quest = 'What you`re name?'

function name(){
 let yourName = prompt(quest, '');
 
 alert(yourName);
 }
 
 name();

 

함수에선 외부 변수에 접근하는 것뿐만 아니라, 수정도 할 수 있습니다.

let quest = 'What you`re name?'

function age(){
 quest = 'How old are you?'
 let yourName = prompt(quest, '');
 
 alert(yourName);
 }
 
 age();

외부 변수는 지역 변수가 없는 경우에만 사용할 수 있습니다.

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

let apple = 'apple'

function fruit (){
 let apple = 'smartphone'
 alert(apple);
 }
 
 fruit(); // smartphone

 

위 예시의 apple처럼 함수 외부에서 선언된 변수는 전역변수라고 부릅니다.

전역 변수는 같은 이름을 가진 지역 변수에 의해 덮어지지 않는다면 모든 함수에서 사용할 수 있습니다.

덮어진다는 위험이 있어서 되도록 사용하지 않는 것이 좋지만 프로젝트 전반에서 사용되는 데이터는 전역 변수에 저장하는 것이 유용한 경우도 있습니다.

 

 

매개변수

매개변수는 인수라고 불리기도 합니다.

function showMessage(from, text) { // 인수: from, text
  alert(from + ': ' + text);
}

showMessage('Ann', 'Hello!'); // Ann: Hello! (*)
showMessage('Ann', "What's up?"); // Ann: What's up? (**)

*, ** 로 표시한 줄에서 함수를 호출하면, 함수에 전달된 인자는 지역변수 from, text에 복사됩니다. 그 후 함수는 지역변수에 복사된 값을 사용합니다.

 

 

기본값

매개변수에 값을 전달하지 않으면 그 값은 undefined가 됩니다.

예시를 통해 알아봅시다. 위에서 정의한 함수 showMessage(from, text)는 매개변수가 2개지만, 아래와 같이 인수를 하나만 넣어서 호출할 수 있습니다.

showMessage("Ann");

이렇게 코드를 작성해도 에러가 발생하지 않습니다. 두 번째 매개변수에 값을 전달하지 않은 것으로 판단하여 text엔 undefiend가 할당될 뿐입니다. 따라서 에러 없이 "Ann: undefined"가 출력됩니다.

매개변수 값을 전달하지 않아도 그 값이 undefined가 되지 않게 하려면 '기본값'을 설정해주면 됩니다. 매개변수 오른쪽에 = 을 붙이고 undefined 대신 설정하고자 하는 기본값을 쓰면 됩니다.

function message(from, text = '메세지가 없습니다'){
   alert( from + ':' + text);
   }
   
message('Ann'); // Ann: 메세지가 없습니다.

이렇게 작성하면 text가 값을 받지 않아도 undefined 대신 기본값 '메세지가 없습니다'가 할당됩니다.

그리고 복잡현 표현식도 기본값으로 설정할 수 있습니다.

function message(from, text = anotherFunction()) {
  // anotherFunction()은 text값이 없을 때만 호출됨
  // anotherFunction()의 반환 값이 text의 값이 됨
}

 

 

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

함수 선언부에서 매개변수 기본값을 설정하는 것 대신 함수가 실행되는 도중에 기본값을 설정할 수 있습니다.

이 경우 매개변수를 undefined와 비교하여 함수 호출 시 매개 변수가 생략되었는지를 확인합니다.

function message(text) {
	if (text === undefined){
    	text = '빈 문자열';
        }
    
    alert(text);
  }
  
  
message(); // 빈 문자열

 

if 문 대신 논리 연산자 || 를 사용할 수 있습니다.

// 매개변수가 생략되었거나 빈 문자열("")이 넘어오면 변수에 '빈 문자열'이 할당됩니다.
function message(text) {
  text = text || '빈 문자열';
  ...
}

 

null 병합 연산자 ?? 를 사용하면 0 처럼 false로 평가되는 값들을 일반 값처럼 처리할 수 있어 좋습니다.

// 매개변수 'count'가 넘어오지 않으면 'unknown'을 출력해주는 함수
function showCount(count) {
  alert(count ?? "unknown");
}

showCount(0); // 0
showCount(null); // unknown
showCount(); // unknown

 

 

 

반환 값

함수를 호출했을 때 함수를 호출한 그곳에 특정 값을 반환하게 할 수 있습니다. 이때 특정 값을 반환 값이라고 합니다.

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 movie(age) {
  if ( !checkAge(age) ) {
    return;
  }

  alert( "영화 상영" ); // (*)
  // ...
}

 

return 문이 없거나 return만 있는 함수는 undefined를 반환합니다.

// 함수가 비어있는 경우

function nothing (){ /* empty */}
alert ( nothing() === undefined); // true

// return 만 있는 경우

function nothing(){
		return;
        }
alert ( nothing() === undefined); // true

 

return을 사용할 때 반환하려는 값이 긴 표현식인 경우 다음을 주의해야 합니다.

// 이렇게 작성하지 마세요
return
  (do + not + follow + this )
  
// 자바스크립트는 return문 끝에 세미콜론을 자동으로 넣기 때문에 다음처럼 작동합니다.
return ;
  (do + not + follow + this )
  

// 따라서 원했던 표현식을 반환하지 못하게 됩니다.

 

만약 표현식을 길게 작성하고 싶다면 다음과 같이 작성해야 합니다.

return (
	This + works
    + fine
    )

이렇게 작성하면 의도한 대로 표현식을 반환할 수 있습니다.

 

 

함수 이름짓기

함수는 어떤 동작을 수행하기 위한 코드를 모아놓은 것입니다. 따라서 함수의 이름은 대부분 동사입니다.

함수의 이름은 가능한 간결하고 명확해야 합니다. 함수가 어떤 동작을 하는지 설명할 수 있어야 합니다. 코드를 읽는 사람은 함수의 이름만 보고도 함수가 어떤 기능을 하는지 힌트를 얻을 수 있어야 합니다.

함수가 어떤 동작을 하는지 축약해서 설명해주는 동사를 접두어로 붙여 함수 이름을 만드는 게 관습입니다. 다만, 티미 내에서 그 뜻이 반드시 합의된 접두어만 사용해야 합니다.

'show'로 시작하는 함수는 대개 무언가를 보여주는 함수입니다.

이 외에 다음과 같은 점두어를 사용할 수 있습니다.

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

위 접두어를 사용하면 아래와 같은 함수를 만들 수 있습니다.

showMessage(..)     // 메시지를 보여줌
getAge(..)          // 나이를 나타내는 값을 얻고 그 값을 반환함
calcSum(..)         // 합계를 계산하고 그 결과를 반환함
createForm(..)      // form을 생성하고 만들어진 form을 반환함
checkPermission(..) // 승인 여부를 확인하고 true나 false를 반환함

 

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

 

 

함수 === 주석

함수는 간결하고, 한 가지 기능만 수행할 수 있게 만들어야 합니다. 함수가 길어지면 함수를 잘개 쪼갤 때가 되었다는 신호로 받아들여야 합니다.

함수를 쪼개는 것은 쉽지 않지만 분리해서 작성하면 많은 장점이 있기에 분리해 작성할 것을 권유합니다.

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

// 첫 번째 코드
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 ); // 소수
  }
}
// 두 번째 코드
function showPrimes(n) {

  for (let i = 2; i < n; i++) {
    if (!findPrime(i)) continue;

    alert(i);  // a prime
  }
}

function findPrime(n) {
  for (let i = 2; i < n; i++) {
    if ( n % i == 0) return false;
  }
  return true;
}

 

두 코드는 동일한 결과를 가져오지만 유지보수 측면에서 두 번째 코드가 더 낫습니다. 이해하는 입장에서 두 번째 코드가 함수의 이름을 보고 어떤 동작을 하는지 예상할 수 있기 때문입니다. 이렇게 이름만 보고도 어떤 동작을 하는지 알 수 있는 코드를 자기 설명적 코드라고 합니다.

 

 

* 요약 *

함수 선언 방법

function 함수이름(복수의, 매개변수는, 콤마로, 구분합니다) {
  /* 함수 본문 */
}
  • 함수에 전달된 매개변수는 함수의 지역변수가 됩니다.
  • 함수는 외부 변수에 접근할 수 있습니다. 하지만 함수 바깥에서 함수 내부의 지역변수에 접근하는 건 불가능합니다.
  • 함수는 값을 반환할 수 있으며 반환하지 않는 경우 undefined가 됩니다.

 

함수의 이름을 지을 땐 다음 규칙을 따릅니다.

  • 함수 이름은 함수가 어떻게 동작하는지 알 수 있어야 합니다.
  • 함수는 동작하기 때문에 이름이 주로 동사입니다.
  • create, get, show, check 등의 접두어를 사용해 이름을 지으면 이름만 보고도 어떤 동작을 하는지 알 수 있습니다.

 

 

* 실습 *

1. a 와 b 중 작은 값을 반환해주는 함수, min(a,b)를 만들어봅시다.

1차 코드
function min (x, y){
    if ( x > y){
        return x
    } else if ( x < y){
        return y
    } else {
        return x
    }
}

2차 코드 (수정)
// x, y가 같은 경우 아무 값이나 반환해도 되는 점을 고려
function min (x, y){
    if ( x > y){
        return x
    } else ( x < y){
        return y
    }
  }

 

 

2. x의 n제곱을 반환해주는 함수를 만들어봅시다.

function pow (x, y){
    return x ** y
}

function squ () {

let num = prompt('제곱할 숫자를 입력해주세요', '');
let double = prompt ('몇 번 제곱할 것인지 입력하세요', '');

alert (pow (num, double));

}

squ();
728x90