44. 자바스크립트 함수

소개

함수는 당신이 자바스크립트에서 할 수 있는 모든 유용한 것들의 중심에 있다. 폭넓게 말하자면, 함수는 프로그램을 논리적인 덩어리들로 나눌 수 있게 해 주는데, 각각의 덩어리들은 기능의 특정한 세부들을 담당한다. 함수는 언어의 중심 기능이고, 자바스크립트의 매력 중 하나는 당신이 직접 함수를 만들고 사용할 수 있다는 것이다. 만약 당신이 PHP나 자바 같은 언어에서의 프로그래밍 경험이 있다면, 자바스크립트에서 함수를 다루면서 집에 있는 것 같은 편안함을 느낄 것이다 – 프로그래밍 경험이 없더라도 걱정할 필요는 없다. 함수는 중요하지만, 머리아플만큼 어려운 것은 아니다. 이 글은 함수를 이해해야 하는 이유에 대해 먼저 다루고, 문법을 설명하면서 함수를 만들고 사용하는 법에 대해 강의할 것이다.

다운로드 받을 수 있는 함수 예제들이 있으니 참고해달라. 또한 이것들은 이 글의 적절한 곳에서 링크되어 있다.

글의 구조는 다음과 같다:

  • 함수:무엇이고, 왜 써야 하는가
  • 함수의 문법
    • 함수 사용하기
    • 인수
    • 반환값
  • 요약
  • 연습문제
  • 저자에 대하여

함수:무엇이고, 왜 써야 하는가

특정한 계산을 수행하려고 할 때 마다 기억을 되살리기 위해 명세서를 뒤적거리길 원하는 사람은 아무도 없다. 이러한 계산 방법을 한 번 정의해 두고, calculateSomething 정도의 이름을 붙여놓은 후 같은 계산이 필요할때마다 호출해서 사용하는 것이 훨씬 좋다. 몇개의 명령어들을 하나로 묶는 이러한 간단한 행동은, 당신이 이 묶음의 내부적인 세세한 동작방식에 주의를 빼앗길 필요 없이 행동에만 주의를 기울이면 된다는 것을 뜻한다. 당신이 만들어내는 함수들을 자바스크립트 핵심 위에 앉아있는 하나의 계층이라고 생각해도 좋다. 당신의 프로그램 내에서 좀 더 이해하기 쉽고 좀 더 상세한 새로운 명령어들을 만들어내는 것이기 때문이다.

이러한 것을 염두에 두고. 함수를 왜 써야 하는지는 매우 직관적인 답을 가지고 있다. 함수란, 프로그램을 구성하는 기본적인 벽돌들과도 같아서, 코드의 목적을 좀 더 알기쉽게 하고 필요할때마다 재사용할수 있게 해준다. 프로그램의 동작을 작은 조각들로 분리하고 그 조각들이 명료하게 한가지 일만 하게끔 한다면 프로그램을 작성하는 것은 좀 더 쉬워질 것이다.

또한, 충분히 주의를 기울여서 함수들을 만들어 내면 당신의 코드를 유지 관리하는 것 역시 쉬워진다. 예를 들어, 내년에는 변경될 서머타임 계산에 대해 생각해 보자. 만약 당신이 이러한 계산을 프로젝트 전반에 걸쳐서 85번 수행했다고 하면, 이것들 전부를 업데이트 하려고 할 때 버그를 만들게 될 것이다. 이것은 반복적이고, 수작업이고, 에러를 만들어낸다. 반면에, calculateDaylightSavings 와 같은 이름의 함수를 만들어 둔다면 함수를 한번 변경하는 것으로 코드 전체에 변경을 적용할 수 있다. 이것은 마치 CSS가 페이지 전체에 걸쳐 스타일을 적용하는 것과 흡사하다. 이러한 방식으로, 함수는 유지보수 과정에서 에러가 생길 확률을 현저히 줄여주며, 성공적으로 이행할 수 있게 해준다.

함수의 문법

함수를 정의하는 것은 상당히 쉽다. 예를 들어, 요소에 랜덤한 배경색을 설정하는 함수를 만들어 보도록 하자:

function setElementBackground() {
  var red = Math.floor(Math.random() * 256);
  var green = Math.floor(Math.random() * 256);
  var blue = Math.floor(Math.random() * 256);

  var obj = document.getElementById('element_to_change');
  if ( obj ) {
    obj.style.background = 'rgb(' + red + ',' + green + ',' + blue + ')';
  }
}

함수가 실행하는 코드들에 대해서는 일단 젖혀두고, 함수 문법의 4가지 중요한 점을 먼저 이야기하겠다:

  1. 함수 선언은 키워드 function 으로 시작한다.
  2. 이어지는 것은 함수의 이름이며, 이 예제에서는 setElementBackground(나는 함수 이름을 쓸 때 보통 낙타 표기법을 사용하곤 한다) 이다. 함수의 이름은 중요한데, 이것을 사용하고 재사용 할 때마다 기억해야 하는 것이기 때문이다. 함수의 이름이, 함수의 동작에 대한 명확한 설명이 되도록 하길 바란다. setElementBackground 와 같은 함수 이름이, coloursAreNice 라든가 crazySetter 같은 것 보다는 훨씬 낫다는 것에 동의할 것이라고 확신한다.
  3. 함수 이름에 뒤에 괄호가 나온다. 괄호 내부에는 함수의 인수가 있는데, 인수를 통해 함수를 좀 더 범용적으로 만들 수 있다. 범용적인 함수는 더 많은 상황에 더 잘 적용할 수 있는 함수이다. 이것은 아주 강력한 개념이지만, 선택적이므로 이것에 대해서는 다음 절에서 좀 더 상세히 다룰 것이다.
  4. 마지막으로, 코드를 포함하는 중괄호로 이어진다. 이것은 자바스크립트 코드 블럭을 의미한다. 이 블럭 안에 있는 모든것들이 함수가 호출될 때마다 순서대로 실행될 것이다.

함수 사용하기

함수를 정의했으니, 코드 내에서 그것을 호출하기 위해서는 다음과 같이 쓰면 된다:

setElementBackground();

이것이 전부다. setElementBackground 내부의 어려운 세부사항에 대해서는 더이상 신경 쓸 필요 없다. 이미 코드를 만들었고, 필요한 곳에서 필요한만큼 재사용하면 된다.

자, 지금 막 만들어낸 함수는 자기 완결적이다. 이것은 같은 행동을 하고, 빠져나간다. 이 함수를 호출하는 코드에서 아무런 입력을 받을 필요도 없고, 어떤 일이 일어났는지 그 호출자에게 알려주지도 않는다. 물론, 자바스크립트는 좀 더 많은 것을 소통할 수 있는 유연한 코드를 만들어 낼 수 있으므로, 함수에 정보를 전달하고 함수로부터 정보를 받는 방법에 대해 좀 더 알아보도록 하자.

인수

함수를 실행할 때 인수를 전달함으로서 함수의 동작에 영향을 미칠 수 있고, 이러한 과정을 통해 함수는 다양한 상황에서 훨씬 더 유연하고 유용하게 된다. 예를 들어, setElementBackground가 배경색을 변경하는 요소에 id를 정의했다(var obj = document.getElementById(‘element_to_change’)). 함수를 호출할 때 마다 페이지의 다른 요소들을 전달한다면, 매번 코드를 복사할 필요가 없으므로 훨씬 유용할 것이다. 인수를 통해 그렇게 할 수 있다.

앞서서, 함수의 정의에는 이름 바로 다음에 괄호가 이어진다고 이야기했다. 이것이 함수의 인수 리스트이다. 함수에 인수를 전달하려면, 콤마로 구분된 변수 리스트를 사용하면 된다. 인수는 원하는만큼 많이 사용할 수 있고, 인수 리스트에서 사용한 변수의 이름들은 다른 변수들과 같은 방법으로 함수 내부에서 참조된다. 이러한 방식으로 업데이트한 setElementBackground 는 다음과 같다( 여기서 직접 테스트해보자):

function setElementBackground( elementID ) {
  var red = Math.floor(Math.random() * 256);
  var green = Math.floor(Math.random() * 256);
  var blue = Math.floor(Math.random() * 256);

  var obj = document.getElementById( elementID );
  if ( obj ) {
    obj.style.background = 'rgb(' + red + ',' + green + ',' + blue + ')';
  }
}

요소 ID를 인수로 지정하여 이 함수를 호출하는 방법은:

setElementBackground( 'element_to_change' );

실수로 인수를 지정하지 않고 함수를 호출한다면, 함수는 undefined 라는 값을 받는다. 의도되지 않은 실수에 대한 대응책을 세우기 위해, 함수 내부에 다음과 같은 코드를 삽입하는것도 좋겠다:

if ( elementID == undefined) {
  // This will evaluate to `true` if the `elementID`
  // variable wasn't provided by the caller.
  // You can then write some code inside this
  //if statement to stop the code from erroring.
}

함수의 인수에 관해서, 혼동스럽지만, 아주 좋은 것은, 인수 리스트의 변수 이름은 함수 안으로 전달되는 변수의 이름과는 아무 상관이 없다 는 것이다. elementID 라는 이름의 인수가 전달되었으면, 자바스크립트는 함수 내부에서 elementID 라는 이름의 변수를 만들어내고, 이렇게 새로 만들어진 변수는 함수 외부의 어떠한 변수와도 관계가 없다. 함수 내부에서 사용된 변수 이름을 함수 외부에서 다시 사용할 수 있고, 외부에서 사용된 변수는 함수 내부의 동작에 영향받지 않을 것이다. 예를 들어:

var elementID = "No change!";
setElementBackground( 'element_to_change' );
alert( elementID ); // Alerts "No change!";

이것은 굉장히 중요한 부수적 효과를 갖는다. 자바스크립트는 함수 내부에서 새로운 변수를 만드는데, 바꿔 말한다면 내부에서 인수에 가한 변경은 전달된(외부의) 변수에 아무런 영향을 미치지 않는다는 것이다. 이러한 주제(영역, scope)에 대해서는 자바스크립트 객체 자바스크립트 최상의 실천법에서 좀 더 다뤄지겠지만, 일단은 짧은 예제부터 보도록 하자. 문자열과, 시작지점을 인수로 전달받는 substring 함수를 다음과 같이 정의하겠다:

function substring( obj, start ) {
  obj = obj.substring(8);
}

var myString = "This is a string!";
substring(myString, 8);
alert(myString); // Alerts "This is a string!"

obj 변수가, 자바스크립트 내장 메서드 substring 를 통해 함수 내부에서 다른 값을 할당받았지만, myString 은 전혀 영향받지 않았다. 함수, substring 내부에 있는 myString의 복사본만이 변경되었다. 외부의 변수는 내부에서 무슨 일이 일어났는지 전혀 알 방법이 없다.

이것은 소통의 문제를 일으킨다. 인수에 가한 변경이 함수 외부에는 아무런 영향을 끼치지 않는다면, 함수는 자신을 호출한 코드에게 어떻게 정보를 전달하겠는가? 지금부터 그것을 살펴보자.

반환값

함수가 특정한 계산을 수행한 뒤, 그 결과를 호출자에게 반환하여 다른곳에서 사용할 수 있도록 하는 것은 무척 자주 있는 일이다. 예를 들어, 우리의 setElementBackground 함수가 다른곳에서 사용될 수 있는 컬러 값의 배열을 반환 한다면 유용할 것이다. 자바스크립트 예약어인 return 을 사용하면 간단하다. 예제를 보자:

function setElementBackground( elementID ) {
  var red = Math.floor(Math.random() * 256);
  var green = Math.floor(Math.random() * 256);
  var blue = Math.floor(Math.random() * 256);

  var obj = document.getElementById( elementID );
  if ( obj ) {
    obj.style.background = 'rgb(' + red + ',' + green + ',' + blue + ')';
  }

  return [ red, green, blue ];
}

두번째 변경점을 직접 테스트해 보자.

이렇게 간단한 것을 추가함으로서, 이제 함수를 호출하고 그 결과를 변수에 저장할 수 있게 되었다:

var my_result = setElementBackground('element_to_change');

함수가 값을 반환할 필요가 없거나, 또는 반환할 값이 없다고 하더라도, true나 false를 반환하게 함으로서 성공이 실행적이었는지 확인해보는 것은 좋은 연습이 될 것이다. 이러한 것을 염두에 두고, setElementBackground 함수에 전달된 elementID 가 실제로 존재하지 않을 경우 false를 반환하도록 변경해보겠다:

function setElementBackground( elementID ) {
  var red = Math.floor(Math.random() * 256);
  var green = Math.floor(Math.random() * 256);
  var blue = Math.floor(Math.random() * 256);

  var obj = document.getElementById( elementID );
  if ( obj ) {
    obj.style.background = 'rgb(' + red + ',' + green + ',' + blue + ')';
    return [ red, green, blue ];
  } else {
    return false;
  }
}

세번째 변경점을 직접 테스트해 보자.

이렇게 함으로서, 반환값을 조사해서 함수가 제대로 실행되었는지 체크해볼 수 있다. 예를 들어:

if ( !setElementBackground('element_does_not_exist') ) {
  alert("Something went wrong!  `element_does_not_exist` doesn't exist!");
}

여기에 더해, return 코드는 즉시 함수의 실행을 멈추고 함수를 호출한 지점으로 값을 반환한다는 점을 기억하기 바란다. return 뒤에 있는 코드는 실행되지 않고 무시된다.

요약

자, 이제 당신의 코드에 함수를 사용하기 위해 필요한 모든 것을 알게 되었다. 함수는 좋은 자바스크립트 코드의 기초적인 파트이며 당신의 프로그램은 좀 더 잘 조직화될 것이고, 명확하고 알기 쉬우며, 재사용하기도 쉬워 질 것이다 – 잘 이름지어진 함수에 코드들을 포장한다면 말이다.

연습문제

  • 함수란 무엇이고, 왜 유용한가?
  • 어떻게 함수를 정의하는가?
  • 함수에 어떻게 정보를 전달하는가? 왜 그렇게 하려고 하는가? 함수로부터 어떻게 정보를 얻어내는가?
  • setElementBackground 함수 내부로 컬러 배열을 전달할 수 있다면 더 좋지 않을까? 다른 인수를 받아들일 수 있도록 코드를 수정하고, 함수 내부에서 랜덤하게 정해진 배경색을 전달된 인수로 덮어쓰도록 해 보라.

저자에 관해

Mike West 는 경험많고 성공한 웹 개발자의 탈을 쓴 철학과 학생이다. 그는 웹 분야에서 10년 넘게 일해오고 있으며, 야후! 의 유럽 뉴스 사이트 개발의 책임을 맡은 팀에서 오랫동안 일했다.

2005년, 텍사스 교외의 광활한 평야를 떠나, Mike 는 독일의 뮌헨에 정착했고 독일어를 익히기 위한 그의 고군분투는 다행히 성공적이다. mikewest.org 가 웹에서의 그의 집이며, 후대를 위해 자신의 글과 링크들을 (천천히)모아 가고 있다. 그가 작성한 코드들은 GitHub 에서 찾아볼 수 있다.

이 글을 다 읽어주셨다면, 댓글을 남겨주세요. 좋았다라는 격려도 좋고, 잘못된 부분을 지적해 주시는 것도 좋습니다. 마음에 드셨다면 아래 Like 버튼을 눌러서 페이스북과 트위터로 소개해 주시면 더욱 좋겠습니다.