본문 바로가기

Frontend Dev/JavaScript

함수 정의 방식 : 함수 선언문(function declaration)과 함수 표현식(function expression)

반응형

 자바스크립트에서 함수를 정의하는 방식은 크게 함수선언문(function declaration)과 함수 표현식(function expression)으로 나눌 수 있다. 

 ✏️ 전체 글을 공부하기에 앞서 요약하자면, 

 함수 선언문(function declaration)은 함수 이름과 함수 내용을 포함하는 방식으로 함수를 정의한다. 이 방식은 코드 어디에서든 호출할 수 있으며, 호이스팅(hoisting)이라는 개념에 따라 함수 선언문을 나중에 작성해도 코드 상단으로 이동하여 먼저 실행된다.

 함수 표현식(function expression)은 변수에 함수를 할당하는 방식으로 함수를 정의한다. 이 방식은 변수에 할당된 함수를 호출하는 방식으로만 사용할 수 있다. 함수 표현식은 변수에 값을 할당하는 것과 동일하게 처리되므로, 함수 선언문과 달리 호이스팅되지 않는다.


 

👾 함수 선언문(function declaration. 함수 선언방식)

 함수 선언 키워드인 function 키워드를 사용하여 함수를 선언하는 방식

function greeting() {
  console.log("hello world");
}

greeting() // ⬅︎ 함수 호출

 

 

👾 함수 표현식(function expression)

 변수 선언 키워드를 사용하여 함수를 표현하는 방식. 함수를 생성하고 변수에 값을 할당하는 것처럼 함수가 변수에 할당된다.

 이 때 함수 이름을 생략할 수 있으며, 이 경우에는 해당 함수를 익명함수로 간주한다. (함수 표현식에서는 이름있는 함수와 익명 함수 모두 사용할 수 있다.)

let greeting = function() {
  console.log("hello world");
};

greeting() // ⬅︎ 함수 호출

함수 표현식은 함수를 값으로 다룰 수 있기 때문에, 함수를 변수에 할당하거나 다른 함수의 인수로 전달할 수 있다.

 

❓ 함수 표현식의 끝에 세미콜론(;)이 붙는 이유

if { … } for {} function f {} 같이 중괄호로 만든 코드 블록 끝엔 세미콜론(;)이 없어도 되지만 함수 표현식은 let greeting = …; 과 같은 구문 안에서 값의 역할을 한다. 코드 블록이 아니고 값처럼 취급되어 변수에 할당된다. 모든 구문의 끝엔 세미콜론을 붙이는게 좋고, 함수 표현식에 쓰인 세미콜론은 함수 표현식 때문이 아니라 구문의 끝이기 때문에 붙여진 것이다.

 

 

👾 함수 표현식 - 익명함수, 즉시실행함수, 재귀함수

익명함수, 즉시실행함수, 재귀함수는 모두 함수 표현식에 포함된다.

(*재귀함수는 함수선언문으로도 정의할 수 있다.)

 

✔️ 익명함수(anonymous function)

: 함수 이름을 생략하고 변수에 함수를 할당하는 함수 표현식

 이름없이 선언한 익명함수는 일반적으로 변수에 할당하여 사용되며(함수 표현식), 다른 함수의 인수로 전달하거나 콜백 함수로 사용된다.

함수 표현식에서는 익명 함수와 이름 있는 함수 모두 사용할 수 있지만, 함수 선언문에서는 이름 있는 함수만을 사용할 수 있다.

익명 함수는 변수에 할당된 게 아니기 때문에 함수 바깥에선 접근할 수 없다.

 

👩🏻‍💻 함수 표현식에서 익명함수와 이름있는 함수 사용 예제

// 익명함수
let greeting = function(name) {
  console.log("hello, " + name);
};

// 이름있는 함수
let greeting = function sayHello(name) {
  console.log("hello, " + name);
};

greeting("Helen"); // Hello, Helen
sayHello("Helen"); // ReferenceError: sayHello is not defined

• 이름있는 함수에서 sayHello 함수는 greeting 변수에서 참조할 수 있지만 외부에서는 참조 할 수 없다.

• 함수 표현식에서 이름 있는 함수를 사용하면 해당 함수 내부에서 자신을 참조할 수 있다. 이를 재귀함수라고 한다.

 

✔️ 즉시 실행 함수(IIFE, Immediately Invoked Function Expression)

: 함수를 정의하자마자 즉시 실행되는 함수 표현식

 즉시 실행 함수는 선언과 동시에 함수가 실행되기 때문에 한 번만 실행되며, 함수명이 없기에 재호출을 할 수 없다.

(function(){
  // 실행문;
})();

• 즉시 실행 함수 내부에서 선언한 변수와 함수는 모두 지역 변수로 취급되기 때문에 외부에서 접근할 수 없으므로, 전역 변수와 충돌을 방지하고 코드의 안정성을 높일 수 있다.

 

👩🏻‍💻 example

(function() {
  let x = 10;
  console.log(x); // 바로 출력된다.
})();
let func = (function(){
  console.log('즉시 실행 함수'); // 바로 출력된다.
})();

func(); // TypeError: instant is not a function

 

✔️ 재귀함수(recursive function)

: 함수 내부에서 자기 자신을 호출하는 함수로 함수 표현식 뿐만 아니라 함수 선언문으로도 정의할 수 있다.

 함수 내부에서 자기 자신을 호출하는 함수로 이를 통해 반복적인 작업을 수행할 수 있다. → 팩토리얼 계산이나 피보나치 수열 계산 등은 재귀 함수를 사용하여 구현할 수 있다.

 재귀 함수는 일반적으로 종료 조건을 포함하고 있어야 하며, 종료 조건이 없으면 함수는 무한히 자기 자신을 호출하며 스택 오버플로우 등의 문제가 발생할 수 있다.

 

👩🏻‍💻 example

// 함수 선언문으로 구현한 재귀함수

function factorial(n){
  if(n === 0){
      console.log('호출 끝');
  }else{
      console.log('호출' + n);
      factorial(n-1); // 재귀함수
  }
}
factorial(10);

// 출력값: 호출10, 호출9, 호출8, ...호출1, 호출 끝
// 함수 표현식으로 구현한 재귀함수

let factorial = function fact(n) {
  if (n === 1) {
    return 1;
  } else {
    return n * fact(n - 1); // 재귀함수
  }
}

console.log(factorial(5)); // 120

 

 

👾 함수 선언문 vs 함수 표현식

 함수를 선언해야 한다면 함수가 선언되기 이전에도 함수를 활용할 수 있는 함수 선언문 방식을 따르는게 좋다. 함수 선언 방식은 코드를 유연하게 구성할 수 있도록 해주고, 가독성도 좋다. 함수 표현식은 함수 선언문을 사용하는게 부적절할 때에 사용하는 것이 좋다.

 

✔️ 함수 선언문과 함수 표현식의 함수 생성 시점

 자바스크립트는 스크립트를 실행하기 전 준비단계에서 전역에 선언된 함수 선언문을 찾고, 해당 함수를 생성한다. 스크립트가 진짜 실행되기 전 "초기화 단계"에서 함수 선언 방식으로 정의한 함수가 생성된다. 스크립트는 함수 선언문이 모두 처리된 이후에서야 실행된다.

 

함수 선언문

: 함수 선언문이 정의되기 전에도 호출할 수 있다. (즉, 전역 함수 선언문은 스크립트 어디에 있느냐에 상관없이 어디에서든 사용할 수 있다.) → 호이스팅

sayHi("John"); // Hello, John

function sayHi(name) {
  console.log(`Hello, ${name}`);
}

 

함수 표현식

: 실제 실행 흐름이 해당 함수에 도달했을 때 함수를 생성한다. 따라서 실행 흐름이 함수에 도달했을 때부터 해당 함수를 사용할 수 있다.

sayHi("John"); // error!

let sayHi = function(name) {
  console.log(`Hello, ${name}`);
};

 

✔️ 함수 선언문과 함수 표현식의 스코프

함수 선언문

: 함수 선언문은 함수가 선언된 코드 블록 안에서만 유효하다.

 엄격 모드에서 함수 선언문이 코드 블록 내에 위치하면 해당 함수는 블록 내 어디서든 접근할 수 있다. 하지만 블록 밖에서는 함수에 접근하지 못한다.

'use strict';

let age = 16;

if (age < 18) {
  welcome(); // 실행됨                                        
  function welcome() {     
    console.log("안녕!"); 
  }                                                 
  welcome(); // 실행됨        

} else {
  function welcome() {
    console.log("안녕하세요!"); 
  }
}

welcome(); // Error: welcome is not defined

 

함수 표현식:

함수가 선언된 코드 블록 밖에서 변수를 미리 선언하여 함수를 할당하면, 코드 블록 밖에서도 함수를 사용할 수 있다.

'use strict';

let age = 16;
let welcome;

if (age < 18) {
  welcome = function() {
    console.log("안녕!");
  };
} else {
  welcome = function() {
    consnole.log("안녕하세요!");
  };
}

welcome(); // 실행됨

 


자료출처: JAVASCRIPT.INFO

✏️ 공부하며 정리한 내용입니다. 잘못된 정보나 더 공유할 내용이 있으면 댓글로 알려주세요!

읽어주셔서 감사합니다 😊

 

반응형