Too Early To Stop
Main
About
Portfolio
Blog
Light
Thumbnail Image
JavaScript 핵심 개념 - 함수#1 (Function)
#JavaScript
2021년 1월 26일

함수의 3가지 정의 방법

함수 리터럴 (함수 선언문)

자바스크립트에서는 함수도 일반 객체처럼 값으로 취급되기 때문에, 객체 리터럴 방식으로 일반 객체를 정의할 수 있는 것처럼 함수도 리터럴 방식으로 정의가 가능합니다.

함수 선언문 방식이 함수 리터럴 형태와 동일한 정의 방법인데, 반드시 함수명이 정의되어 있어야 합니다.

C나 C++와 함수를 정의하는 방법이 비슷하지만, 동적 타입이라는 특징을 가진 자바스크립트에서는 변수 타입을 명시하지 않습니다.

function add(a, b) {
  return a + b;
}

함수 표현식

함수도 하나의 값처럼 취급되는 자바스크립트의 특징 때문에 함수도 변수에 할당이 가능합니다.

이와 같이 함수 리터럴 방식으로 함수를 정의하고, 이를 변수에 할당하여 함수를 생성하는 방식을 함수 표현식 방식이라고 합니다.

var add = function (a, b) {
  return a + b;
};

위의 예시에서는 함수의 이름이 없는 익명 함수를 선언했는데, 이와 같은 방법을 익명 함수를 이용한 함수 표현식 방법이라고 부릅니다.

이와 달리 함수 이름이 포함된 경우에는 이를 기명 함수 표현식이라 부르고, 정의한 함수의 이름을 재귀 호출이나 디버그 시의 함수 식별 등을 위해 사용됩니다.

하지만 함수 표현식에서 사용된 함수 이름은 정의된 함수 내부에서만 사용 가능할 뿐, 외부에서는 접근이 불가능합니다.

그럼 함수 선언문 방식으로 정의한 함수는 어떻게 함수 이름으로 접근할 수 있을까요?

이유는 자바스크립트 엔진에 의해 함수 표현식 방식으로 변환되기 때문입니다.

위의 함수 선언문 방식의 예제가 다음과 같이 변환됩니다.

var add = function add(a, b) {
  return a + b;
};

결국 실제로는 함수 이름을 통해 호출하는 것이 아닌, add 함수 변수를 통해 함수를 호출하는 방식입니다.

Function() 생성자 함수를 통한 함수 정의

자바스크립트에 내장된 생성자를 통해 정의하는 방법입니다.

내부적으로는 선언 방식에 상관 없이 모든 함수가 생성자 함수로 정의됩니다.

사용 방법은 다음과 같습니다.

// 사용 방법
new Function (arg1, arg2, ..., argN, functionBody)

// 실제 사용 예시
var add = new Function('a', 'b', 'return a + b');

함수 호이스팅

함수를 생성하는 방식에는 총 3가지 방법이 있는데, 모두 같은 기능의 함수를 생성하지만 동작 방식에 약간의 차이점이 존재합니다.

이 차이점 중 하나가 바로 함수 호이스팅인데, 함수 호이스팅이란 함수의 유효 범위가 코드의 맨 처음부터 시작하는 것입니다.

코드 읽기를 난해하게 만들 수 있는 자바스크립트의 특징입니다.

console.log(add(1, 2)); // 3 (함수 호이스팅에 의해 함수 정의 전에도 사용 가능)

function add(a, b) {
  return a + b;
}

console.log(add(3, 4)); // 7

함수 호이스팅이 발생하는 이유는 변수의 생성과 초기화의 작업이 분리되어 진행되기 때문인데, 이를 자세하게 알아보기 위해서는 실행 컨텍스트에 대해 알아야합니다.

하지만 실행 컨텍스트에 대해서는 잘 모르기 때문에 이 개념 없이 설명해보자면 자바스크립트에서는 정의된 변수와 함수를 생성하고, 변수에는 먼저 undefined를 할당합니다.

그 후, 변수 초기화는 해당 변수의 표현식이 실행되어야 값이 할당됩니다.

따라서 함수 선언문 방식은 변수에 값을 할당하는 것이 아니기 때문에 정의된 변수 또는 함수를 생성할 때에 즉각적으로 함수 객체가 할당이 되어 코드 맨 처음에서도 함수 호출이 가능합니다.

console.log(add(1, 2)); // Uncaught Type Error (함수 호이스팅이 발생하지 않음)

var add = function (a, b) {
  return a + b;
};

console.log(add(3, 4)); // 7

하지만 함수 표현식 방식은 위의 실행 컨텍스트 글에 따르면 정의된 변수를 생성하고 undefined를 할당하며, 표현식이 실행되기 전까지는 초기화가 되지 않기 때문에 함수 정의 후에 호출이 가능합니다.

따라서 코드의 구조를 엉성하게 만들 수 있는 함수 호이스팅을 방지하기 위해 함수 표현식의 사용을 권장하고 있습니다.

함수의 다양한 형태

콜백 함수

자바스크립트 함수 표현식에서 함수 이름은 선택 사항이며, 이와 같이 함수 이름이 존재하지 않는 함수를 익명 함수라고 했습니다.

여기서 설명하려고 하는 콜백 함수가 위와 같은 익명 함수의 대표적인 용도입니다.

익명 함수이기 때문에 명시적으로 호출하기 위한 함수가 아닌, 이벤트 발생 또는 특정 시점에 호출되는 함수를 말합니다.

아래의 예시와 같이 콜백 함수를 사용할 수 있죠.

setTimeout(function () {
  console.log('Called Callback Function.');
}, 3000);

다음은 특정 시간 뒤에 인자로 넘긴 함수를 실행시키는 setTimeout 함수입니다.

3초 후에 텍스트를 출력하는 간단한 예제인데, 특정 시점에 실행할 함수를 익명 함수인 텍스트를 출력하는 함수로 연결하여 콜백 함수로 등록했습니다.

즉시 실행 함수

익명 함수를 응용한 형태인 즉시 실행 함수는 말 그대로 함수를 정의함과 동시에 실행하는 함수입니다.

아래의 예시와 같이 즉시 실행 함수를 사용할 수 있습니다.

(function (text) {
  console.log(text);
})('Hello, World!');

이와 같이 함수 리터럴을 소괄호로 둘러싸고, 이 함수가 바로 호출될 수 있도록 인자값을 담은 괄호쌍을 추가하면 즉시 실행 함수가 정의됩니다.

따라서 다음 예시에서는 Hello, World! 텍스트를 익명 함수의 인자값으로 넘긴 것입니다.

즉시 실행 함수는 재호출이 불가능하기 때문에 이런 특징을 이용해 단 한 번의 실행으로만 초기화를 하는 코드 부분에 유용하게 사용될 수 있습니다.

그런데 즉시 실행 함수는 유명한 여러 라이브러리에서도 많이 보이는 또 다른 용도가 있습니다.

그 용도는 바로 객체 지향 프로그래밍의 특징 중 하나인 캡슐화인데요, 캡슐화란 변수와 메서드들을 하나로 묶고, 일부 구현 내용을 외부로부터 감추어 은닉하는 것입니다.

자바스크립트에서는 함수 유효 범위를 지원하기 때문에 이와 같은 캡슐화가 가능합니다.

즉, 함수 내의 변수는 그 함수 내부에서만 유효할 뿐이지 전역 범위에서는 유효하지 않다는 말입니다.

따라서 jQuery, Underscore와 같은 유명 라이브러리는 즉시 실행 함수 내에 라이브러리 구현 코드를 추가하여 외부에서 접근을 못하게 할 뿐더러 전역 네엠스페이스를 더럽히지 않아 변수 충돌 문제를 방지할 수 있습니다.

내부 함수

자바스크립트에서는 함수 내부에서 다시 함수 정의가 가능한데, 이와 같이 함수 내부에 정의된 함수를 내부 함수라고 부릅니다.

클로저와 같은 자바스크립트의 매력적인 기능을 구현할 수 있게 만든 중요한 함수입니다.

또, 부모 함수 코드에서의 접근을 막은 독립적인 헬퍼로도 사용이 가능합니다.

여기서 중요한 점이 하나 보이시나요?

즉시 실행 함수에서도 찾아볼 수 있다 시피 함수 내부의 변수는 바깥 범위에서 접근이 불가능합니다.

하지만 함수 내부에서는 바깥 범위의 변수에도 접근이 가능합니다.

이런 현상이 일어나는 이유는 바로 자바스크립트의 스코프 체이닝 때문입니다.

스코프 체이닝은 실행 컨텍스트에 대해 알아야 자세하게 이해할 수 있지만, 이에 대한 설명 없이 간단하게 개념을 풀어보겠습니다.

자바스크립트는 전역 및 함수 단위로 컨텍스트라는 것을 가지게 되는데, 이 컨텍스트 안에 변수를 저장해둡니다.

그리고 연결 리스트와 유사한 형식으로 스코프 정보를 가지게 되어 만약 해당 컨텍스트에서 변수를 찾지 못한다면 그 바깥 컨텍스트로 넘어가 변수를 찾습니다.

이런 이유 때문에 내부 함수에서 외부 함수의 변수에 접근이 가능한 것입니다.

함수를 리턴하는 함수

함수에 대한 더 많은 설명을 담은 다음장에서 설명할 이야기인, 함수가 일급 객체라는 특징 때문에 자바스크립트에서는 함수를 통해 더 다양한 활용이 가능합니다.

함수를 호출함과 동시에 다른 함수로 치환하거나, 자신을 재정의하는 함수로 구현할 수 있습니다.

다음 예시를 확인해봅시다.

var fibo = function () {
  var a = 0,
    b = 1;
  console.log(a);

  return function () {
    var tmp = a + b;
    a = b;
    b = tmp;

    console.log(tmp);
  };
};

fibo = fibo(); // 0

for (var i = 0; i < 5; i++) fibo(); // 1 2 3 5 8

이렇게 자바스크립트의 유연한 성질을 가지고 피보나치 값을 반환하는 fibo 함수를 정의했습니다.

처음 fibo 함수가 호출되면 처음 값인 0이 출력되지만, 함수가 계속 호출되면서 다음 피보나치 값도 계속해서 출력됩니다.


Source

  • 인사이드 자바스크립트 도서
Prev
2020년을 돌아보며
Next
JavaScript 핵심 개념 - 객체 (Object)
Developer Hyun
ⓒ Copyright