profile image

L o a d i n g . . .

반응형

함수

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

 

함수 선언

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

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

매개변수가 없을 수도 있으며, 만약 매개변수가 여러 개 있다면 각 매개변수를 콤마로 구분한다.

이어서 함수 본문(body)을 중괄호로 감싸 붙여 주면 된다.

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

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

showMessage();
showMessage();

 

지역 변수

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

function showMessage() {
    let message = "Hello, I'm JavaScript!";  // local variable

    alert(message);
}

showMessage();  // Hello, I'm JavaScript!
alert(message); // <- error!

 

외부 변수

함수 내부에서 함수 외부의 변수인 외부 변수(outer variable)에 접근할 수 있다.

let userName = 'John';

function showMessageName() {
    userName = "Bob";   // 외부 변수 수정 가능

    let message = "Hello, " + userName;
    alert(message);
}

alert(userName);    // 함수 호출 전이므로 John이 출력된다.

showMessageName();  // Bob 변경 후, Hello, Bob이 출력된다.

alert(userName);    // 함수에 의해 Bob으로 값이 변경되었다.

외부 변수는 동일한 이름의 지역 변수가 없는 경우에만 사용할 수 있다.

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

function showMessageName2() {
    let userName = "Bob";   // 같은 이름을 가진 지역 변수를 선언하면,

    let message = "Hello, " + userName; // 지역 변수를 우선시하게 된다.
    alert(message);
}

 

전역 변수

위 예시의 userName처럼, 함수 외부에 선언된 변수는 전역 변수(global variable)라고 부른다.

전역 변수는 같은 이름을 가진 지역 변수에 의해 가려지지만 않는다면 모든 함수에서 접근할 수 있다.

단, 변수는 연관되는 함수 내에 선언하고 전역 변수는 되도록이면 사용하지 않는 편이 좋다.

프로젝트 전반적으로 사용되는 데이터는 전역 변수에 저장하는 게 유용한 경우도 존재한다.

 

매개변수

매개변수(parameter)를 이용하면 임의의 데이터를 함수 안에 전달할 수 있다.

function showMessage(from, text) {
    alert(from + ": " + text);
}

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

함수에 전달된 인자는 지역변수 fromtext에 복사되고, 그 후 함수는 지역 변수에 복사된 값을 사용한다.

이렇게 지역 변수로의 복사를 하기 때문에, 함수 내부에서 변수의 값을 변경해도 함수 바깥의 원래 매개변수가 변경되지는 않음에 유의한다.

function showMessage(from, text) {
    from = '*' + from + "*";
    alert (from + ": " + text);
}

let from = "Ann";
showMessage(from, "Hello");     // *Ann*: Hello

// 함수는 복사된 값을 사용하기 때문에 함수 바깥의 "from"은 값이 변경되지 않는다.
alert(from);        // Ann

 

기본값

매개변수에 값을 전달하지 않으면 그 값은 undefined가 된다. (에러 없음)

showMessage("Ann");     // Ann: undefined

매개변수에 값을 전달하지 않아도 그 값이 undefined가 되지 않게 하려면, 다음과 같이 '기본값(default value)'을 설정해 준다.

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

showMessage("Ann");     // Ann: no text given

아래와 같이 복잡한 표현식도 기본값으로 설정할 수 있다.

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

 

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

function showMessage(text) {
    if (text == undefined) {
        text = 'empty message';
    }
}

function showMessage(text) {
    text = text || 'empty';
}

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을 만나면 함수 실행이 즉시 중단되며, 함수를 호출한 곳에 값을 반환하게 된다.

function checkAge(age) {
    if (age >= 18) {
        return true;
    } else {
        return confirm("Do you have permission from your parents?");
    }
}

let age = prompt("How old are you?", 18);

if (checkAge(age)) {
    alert("Access granted");
} else {
    alert("Access denied");
}

반환값 없이 return만 해서 함수를 즉시 종료하는 것도 가능하다.

function showMovie(age) {
    if (!checkAge(age)) {
        return;
    }

    alert("Showing you the movie");
    // ...
}

 

 

return문이 없는 함수도 undefined를 반환한다.

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

 

return 지시자만 있는 경우에도 undefined를 반환한다. return == return undefined.

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

 

return과 값 사이에 절대 줄 삽입을 하지 말자.

return//;  // enter를 넣게 되면 세미콜론이 붙은 것과 동일하게 동작한다.
(some + long + expression + or + whatever * f(a) + f(b))
return (    // multi-line으로 작성하고 싶은 경우, 다음과 같이 작성한다.
    some + long +
    expression +
    or +
    whatever * f(a) + f(b)
)

 

함수 이름 짓기

함수는 어떤 동작을 수행하기 위한 코드이기 때문에, 함수의 이름은 대개 동사이다.

함수 이름은 가능한 간결하고 명확해야 하며, 함수 이름만 보고도 어떤 기능을 하는지 나타낼 수 있어야 한다.

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

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

독립적인 두 개의 동작은 독립된 함수 두 개에서 나누어 수행할 수 있게 해야 한다.

  • getAge 함수는 나이를 얻어오는 동작만 수행해야 한다. alert창에 나이를 출력하는 동작은 이 함수에서 처리하지 않는 게 좋다.
  • createForm 함수는 form을 만들고 이를 반환하는 동작만 해야 한다. form을 문서에 추가하는 동작이 해당 함수에 들어가 있으면 좋지 않다.

팀에서 만든 접두어 규칙이 있다면 해당 규칙을 반드시 따라야 한다.

 

함수 == 주석

함수가 길어지면 함수를 잘게 쪼갤 때가 되었다는 신호로 받아들여야 한다. 함수를 쪼개는 게 쉬운 작업은 아니지만, 분리하여 작성하면 많은 작성이 있기 때문에 분리하는 것을 권장한다.

간결한 함수는 테스트와 디버깅을 쉽게 한다. 그리고 함수 자체로도 주석의 역할까지 한다.

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 (!isPrime(i)) continue;

        alert(i);
    }
}

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

 

요약

function 함수이름(복수의, 매개변수) {
        /* 함수 본문 */
}
  • 함수에 전달된 매개변수는 복사를 거쳐 함수의 지역변수가 된다.
  • 함수에서 외부 변수에 접근할 수 있다. 단, 함수 밖에서 함수의 지역변수에 접근하는 건 불가능하다.
  • 함수는 값을 반환할 수 있다. 값을 반환하지 않는 경우, return undefined와 동일하다.

 

과제

"else"는 정말 필요한가요?

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

function checkAge(age) {
    if (age > 18) {
        return true;    // 18세 이상은 여기서 return 처리가 되기 때문에
    }                   // else문이 없어도 18세 미만은
    return confirm('보호자의 동의를 받으셨나요?');  // 해당 return 처리된다
}

 

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

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

 

min(a, b) 함수 만들기

  • 다음과 같이 동작하는 함수 만들기
min(2, 5) == 2
min(3, -1) == -1
min(1, 1) == 1
function min(a, b) {
    return a < b ? a : b;
}

 

pow(x, n) 함수 만들기

function showPrompt() {
    let x = prompt("x를 입력하세요.", '');
    if (x == undefined || x == '') {
        alert("유효하지 않은 x입니다.");
        return;
    }

    let n = prompt("n을 입력하세요.", '');
    if (n == undefined || n == '' || n < 1) {
        alert("유효하지 않은 n입니다. \n자연수를 입력해 주세요.");
        return;
    }

    alert(pow(x, n));
}

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

showPrompt();

 

 

 

해당 포스트는 'The Modern JavaScript Tutorial' 문서를 읽으며 개인 백업용으로 메모하였습니다.

javascript.info/

 

The Modern JavaScript Tutorial

We want to make this open-source project available for people all around the world. Help to translate the content of this tutorial to your language!

javascript.info

 

반응형
복사했습니다!