전체 페이지뷰

2018년 10월 31일 수요일

자바스크립트의 함수


function



스크립트 내에서 같은 작업을 반복하는 경우는 매우 많습니다.
이런 작업의 기능을 하나로 묶어둔 함수는 프로그램의 주된 "building block"이라 할 수 있습니다.

우리는 이미 내장 함수인 alert(message), prompt(message, default), confirm(question)을 살펴본 적이 있습니다. 이제는 직접 함수를 만들 차례입니다.

함수 선언

함수를 만들기 위해서는 선언을 먼저 해야 합니다.

function showMessage() {
  alert'Hello everyone!' );
}
cs
와 같은 형태로 사용됩니다.

function이라는 키워드가 먼저오고 그 다음 함수이름과 괄호 안에 인자(여기서는 비어있음)가 옵니다. 다음 괄호안에 함수의 내용을 작성하면 됩니다.

그리고 함수를 호출할 때는
showMessage()
로 호출합니다.

local variable

로컬 변수와 전역 변수 부분을 뛰어넘을까 했지만, 만에 하나라도 제 글을 보시는 분들이 있다면 도움 되시라고 간략히 옮겨봅니다.

로컬 변수는 함수내에서 선언되고, 함수 내에서만 사용되는 변수입니다.
function showMessage() {
  let message = "Hello, I'm JavaScript!"// local variable
  alert( message );
}
showMessage(); // Hello, I'm JavaScript!
alert( message ); // <-- Error! 이 변수는 함수내에서만 사용가능 
cs


Outer variable

함수는 함수 외부에서 선언된 변수에도 접근 가능합니다.
let userName = 'John';
function showMessage() {
  let message = 'Hello, ' + userName;
  alert(message);
}
showMessage(); // Hello, John
cs

외부 변수에 접근 가능할 뿐만 아니라 수정도 가능합니다.

let userName = 'John';
function showMessage() {
  userName = "Bob"// (1) changed the outer variable
  let message = 'Hello, ' + userName;
  alert(message);
}
alert( userName ); // John before the function call
showMessage();
alert( userName ); // Bob, the value was modified by the function
cs

이 외부변수의 사용은 내부변수가 없을 때에만 이루어집니다. 만약 외부변수와 이름이 같은 지역변수가 선언되어도 둘은 다른 것으로 간주되어 따로 사용되는데, 간혹 내부 변수 선언 시 let을 사용하는 것을 잊게 되면 실수로 외부 변수가 수정되는 일이 일어납니다.

아래의 예는 외부/내부 변수 이름이 같았을 때 입니다.
let userName = 'John';
function showMessage() {
  let userName = "Bob"// declare a local variable
  let message = 'Hello, ' + userName; // Bob
  alert(message);
}
// the function will create and use its own userName
showMessage();
alert( userName ); // John, unchanged, the function did not access the outer variable
cs


이 외부 변수는 프로젝트 내에서 모두 접근 가능하여 전역변수라고도 불립니다.



Parameters


우리는 파라미터(매개 변수)를 통해 함수에 임의의 데이터를 넘겨줄 수 있습니다.

아래의 예는 fromtext라는 두개의 인수를 가지는 함수입니다.
function showMessage(from, text) { // arguments: from, text
  alert(from + ': ' + text);
}
showMessage('Ann''Hello!'); // Ann: Hello! (*)
showMessage('Ann'"What's up?"); // Ann: What's up? (**)
cs

함수 호출시 넘겨준 인자는 지역변수 fromtext에 복사되어 사용됩니다.


Default value

매개변수가 제공되지 않으면 그 값은 undefined가 됩니다.
예를 들어서 위에 보여드린 showMessage( from, text )함수에 한개의 인수만을 넣고 아래처럼 호출해도
showMessage("Ann");
cs

에러가 나지 않으며, "Ann: undefined"라는 출력이 이루어집니다.
만약 인수의 기본값을 설정하고 싶으면 아래와 같은 형식으로 = 기호 뒤에 특정하면 됩니다.

function showMessage(from, text = "no text given") {
  alert( from + ": " + text );
}
showMessage("Ann"); // Ann: no text given
cs

여기서 기본값은 "no text given"이라는 문자열이었습니다만 훨씬 복잡한 표현식도 올 수 있어서 다음과 같은 방식도 가능합니다.
function showMessage(from, text = anotherFunction()) {
  // anotherFunction(): text가 주어지지 않을 때만 실행됨
  // 그 결과가 text의 값이 됨
}
cs


예전 자바 스크립트에서는 이 디폴트를 지원하지 않아서 아래처럼 사용하기도 했습니다. 참고하시기 바랍니다.

function showMessage(from, text) {
  if (text === undefined) {
    text = 'no text given';
  }
  alert( from + ": " + text );
}
cs
이처럼 명시적으로 undefined를 체크하거나


function showMessage(from, text) {
  // if text is falsy then text gets the "default" value
  text = text || 'no text given';
  ...
}
cs
|| 연산자를 사용했습니다.



Returning a value

함수는 그 결과로서 어떤 값을 리턴할 수 있습니다.
아래는 두개의 수를 더하는 그 간단한 예입니다.

function sum(a, b) {
  return a + b;
}
let result = sum(12);
alert( result ); // 3
cs

함수의 어느 위치에나 올 수 있는 return 지시문을 만나면 함수가 멈추고 값이 반환됩니다.

하나의 함수에 아래와 같이 여러 개의 return이 들어갈 수도 있습니다.
function checkAge(age) {
  if (age > 18) {
    return true;
  } else {
    return confirm('Got a permission from the parents?');
  }
}
let age = prompt('How old are you?'18);
if ( checkAge(age) ) {
  alert'Access granted' );
else {
  alert'Access denied' );
}
cs


return 뒤에 아무것도 오지 않을 수도 있습니다. 그러면 함수를 바로 빠져나오게 됩니다.
function showMovie(age) {
  if ( !checkAge(age) ) {
    return;
  }
  alert"Showing you the movie" ); // (*)
  // ...
}
cs



함수가 아무 값도 리턴하지 않는 경우와, 빈 return 인 경우


아무 값도 리턴하지 않는 경우, 실제로는 undefined를 리턴하는 것과 같습니다.
function doNothing() { /* empty */ }
alert( doNothing() === undefined ); // true
cs

빈 리턴문이 있는 경우도 return undefined와 결과가 같습니다.
function doNothing() {
  return;
}
alert( doNothing() === undefined ); // true
cs


* return 다음에 올 것이 길다고 해도 새 줄에 써서는 안 됩니다.

return
 (some + long + expression + or + whatever * f(a) + f(b))
cs
이렇게 쓰면 동작하지 않습니다. 왜냐하면 자바스크립트가 자동으로 return 뒤에 세미콜론을 넣기 때문입니다.

return;
 (some + long + expression + or + whatever * f(a) + f(b))
cs
이렇게 인식되어 바로 빈 return문이 되어 버립니다.



함수 이름짓기


함수는 대개 어떤 action을 표현합니다. 따라서 이름을 동사로 하는 경우가 많습니다. 간단하지만 함수가 하는 일을 정확하게 표현해야 하죠. 읽는 이가 무엇을 위한 것인지 쉽게 알수 있도록 말입니다.

함수가 하는 일을 구분지어 동사접두어를 사용하는 것은 널리 사용되는 방법입니다. 물론 팀원 간에 공감대가 있어야 하겠죠.

에를 들어 show로 시작하는 함수는 대개 무언가를 보여주는 역할을 합니다.

이런 식입니다.

  • "get..." : 값을 리턴하는 용도
  • "calc..." : 무언가를 계산하는 용도
  • "create.." : 무언가를 만드는 용도
  • "check..." : 무언가를 체크하거나 boolean 값을 반환하는 등의 용도
이 실례는 다음과 같습니다.
showMessage(..)     // shows a message
getAge(..)          // returns the age (gets it somehow)
calcSum(..)         // calculates a sum and returns the result
createForm(..)      // creates a form (and usually returns it)
checkPermission(..) // checks a permission, returns true/false
cs

접두어를 적절히 사용하면 함수 이름을 보기만 해도 어떤 일을 하는지, 어떤 값을 리턴하는지 알수가 있습니다.


하나의 함수에 하나의 액션

함수는 그 이름이 뜻하는 딱 한가지의 일만 해야 합니다.

두 개의 독립된 임무를 수행하려면 그에 해당하는 두 개의 함수가 호출되도록 만들어야 겠습니다.

그것을 따르지 않는 나쁜 경우를 살펴봅시다


  • getAge 함수가 나이를 가져올 뿐만 아니라 alert로 보여주는 경우
  • createForm 함수가 서식을 수정하거나 추가하는 일까지 하는 경우
  • checkPermission 함수가 허가를 체크하면서 acess granted/denied 를 보여주는 경우


아주 짧은 함수명

아주 자주 사용되는 함수는 극히 짧은 이름을 지어주는 경우가 있습니다.
예를 들어 JQuery 프레임워크에는 $라는 함수가 있고, LoDash 라이브러리에는 _라는 이름의 함수가 있습니다.
이 경우는 예외적인 경우이며, 대부분의 경우 짧더라도 뜻을 명확히 알 수 있는 이름을 지어줘야 합니다.


함수 == 주석

함수는 짧고 한 가지의 일만 해야한다고 말했습니다. 만약에 길어질 것 같으면 작은 함수들로 나누어야 합니다. 이렇게 하는 일이 어떨 때는 쉽지 않지만 가치있는 일입니다.

독립적인 함수는 테스트와 디버깅이 쉬울 뿐 아니라 그 자체로 훌륭한 주석의 역할을 합니다.

예를 들어 n까지의 정수 중에서 소수를 보여주는 showPrimes(n)이라는 아래의 두 가지 함수를 생각해 봅시다.

첫 번째는 라벨을 사용하는 방법입니다.
function showPrimes(n) {
  nextPrime: for (let i = 2; i < n; i++) {
 
    for (let j = 2; j < i; j++) {
      if (i % j == 0continue nextPrime;
    }
 
    alert( i ); // a prime
  }
}
cs


두 번째는 소수판정을 위한 isPrime(n)이라는 또 하나의 함수를 사용하는 방법입니다.
function showPrimes(n) {
 
  for (let i = 2; i < n; i++) {
    if (!isPrime(i)) continue;
 
    alert(i);  // a prime
  }
}
 
function isPrime(n) {
  for (let i = 2; i < n; i++) {
    if ( n % i == 0return false;
  }
  return true;
}
cs

두 번째가 더 이해하기 쉽지 않습니까? 코드 내용을 분석할 것도 없이 isPrime이라는 이름만 봐도 내용을 알 수 있습니다. 이런 코드를 self-describing 하다고 부릅니다.

댓글 없음:

댓글 쓰기