본문 바로가기
Javascript study

[Javascript] 함수 표현식

by 카누가 좋아요 2023. 7. 18.

📌 참고 사이트

함수 표현식 (javascript.info)

 

함수 표현식

 

ko.javascript.info

 

 

 

📋 JS에서의 함수 표현식

📍 함수 선언문 방식으로 함수 생성하기

이전 시간에는 함수를 만들 때 함수 선언문 방식으로 함수를 만들었다.

 

function sayHi() {
  alert("Hello");
}

 

 

📍 함수 표현식으로 함수 생성하기

JS에서는 다른 언어에서처럼 함수를 특별한 동작을 하는 구조로 취급하지 않고, 특별한 종류의 값으로 취급한다. 따라서 다음과 같이 함수 표현식(function expression)으로도 함수를 만들 수 있다.

(sayHi() 처럼 괄호를 붙여 호출할 수 있기 때문에 일반적인 값과 완전히 같지는 않지만 본질은 같다.)

 

let sayHi = function() {
  alert("Hello");
};     // 함수가 값의 역할을 하므로 이 부분이 구문의 끝이 되고, 세미콜론을 붙이는 것이 좋다.

 

함수 표현식 방식에서는 함수를 생성한 후, 변수에 값을 할당하는 것처럼 함수가 변수에 할당되었다.

JS에서 함수는 값이기 때문에 변수에 할당될 수 있는 것이고, 또한 그 값을 출력하는 것도 가능하다.

 

alert(sayHi);
// 함수 소스 코드 자체가 그대로 출력됨. (string형)
// function() {
//   alert("Hello");
// };

 

❗ 어떤 언어에서는 괄호 없이 함수 이름만 언급해도 그 함수가 실행되지만 JS에서는 괄호가 있어야만 함수 호출이 가능하므로 위 코드의 경우 함수가 실행되지 않는다. 그저 sayHi에 저장된 값(함수 코드 자체)이 출력될 뿐이다.

 

변수에서처럼 함수를 복사해 다른 변수에 할당하는 것도 가능하다. 

 

// 함수 생성
function sayHi() {
  alert("Hello");
}

// 함수 복사
let func = sayHi;     

// 함수 실행 (본래 함수와 복사된 함수 모두 정상적으로 실행)
sayHi();     // Hello
func();     // Hello

 

* 만약 func = sayHi() 라는 식으로 작성하면 func에 sayHi 함수의 반환값인 undefined가 저장되었을 것이다. but sayHi 함수 그 자체를 할당하였으므로 func에는 sayHi 함수의 소스 코드 자체(문자열)가 할당되어 있다.

 

💡 문자열이나 숫자 등의 일반적인 값들은 데이터를 나타내고, 함수는 어떤 동작을 나타낸다.

JS에서 함수는 동작을 대변하는 값이 될 수 있어 변수 간 전달이 가능하고, 그 동작이 필요할 때 그 값을 실행 가능하다.

 

 

 

📋 콜백 함수

📍 콜백 함수 사용 예시

매개변수가 3개 있는 함수인 ask(question, yes, no)를 작성해 보자.

ask 함수는 반드시 질문(question)을 해야 하고, 사용자의 답변에 따라 yes()나 no()를 호출한다.

➡️ question : 질문

➡️ yes : "Yes"라고 답한 경우 실행되는 함수

➡️ no : "No"라고 답한 경우 실행되는 함수

 

function ask(question, yes, no) {
  if (confirm(question)) yes();     // 사용자가 확인을 누르면 showOk 함수 실행
  else no();     // 사용자가 취소를 누르면 showCancel 함수 실행
}

function showOk() {
  alert('동의하셨습니다.');
}

function showCancel() {
  alert('취소 버튼을 누르셨습니다.');
}

ask('동의하십니까?', showOk, showCancel);
// 함수 showOk와 showCancel이 ask 함수의 인수로 전달
// showOk는 위에서 ask 함수의 매개변수 yes에 복사, showCancel는 매개변수 no에 복사됨.

 

위에서 ask 함수의 인수로 들어간 showOk 함수showCancel 함수 같은 함수들을 콜백 함수(콜백)라고 한다.

즉, 함수를 함수의 인수로 전달하고, 필요할 경우 전달된 그 함수를 호출하는 것이 콜백의 개념이다.

위처럼 함수명을 전달해도 되지만 함수 소스 코드 자체를 인수로 전달해도 똑같이 작동한다.

 

❓ 익명 함수 (anonymous function)

ask 함수에 함수명이 아닌 함수 소스 코드 자체를 인수로 전달하는 코드를 작성해 보겠다.

 

function ask(question, yes, no) {
  if (confirm(question)) yes();
  else no();
}

ask(
  "동의하십니까?",
  function() {alert("동의하셨습니다.");},     // 익명 함수
  function() {alert("취소 버튼을 누르셨습니다.");}     // 익명 함수
);

 

위에서 ask 함수 안에 2개의 이름이 없는 함수가 선언되어 있는 것을 볼 수 있는데, 이를 익명 함수라 한다.

위에서의 익명 함수들은 변수에 할당한 것이 아니기 때문에 ask 바깥에서는 접근이 불가하다.

 

 

 

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

📍 함수 표현식과 함수 선언문의 차이

1️⃣ 문법에서 차이가 있다.

➡️ 함수 선언문 : 코드 흐름 중간에 독자적인 구문 형태로 존재한다.

➡️ 함수 표현식 : 표현식(할당 연산자 = 사용)이나 구문 구성 내부에 생성된다. 

 

 

2️⃣ 자바스크립트 엔진이 언제 함수를 생성하는지에 차이가 있다.

➡️ 함수 선언문

함수 선언문이 정의되기도 전에 함수 호출이 가능하므로 전역 함수 선언문은 스크립트 어디에 위치하든 어디서나 사용 가능하다.

이는 JS의 내부 알고리즘에 의해 스크립트 실행 전 전역으로 선언된 함수 선언문을 찾고, 해당 함수를 생성하기 때문에 가능한 일이다. 스크립트는 함수 선언문이 모두 처리된 이후에서야 실행된다.

 

sayHi('John');     // Hello, John (오류 발생 X)

function sayHi(name) {
  alert(`Hello, ${name}`);
}

 

➡️ 함수 표현식

스크립트 실행 중 흐름이 해당 함수에 도달했을 때 함수를 생성하므로 그 때부터 해당 함수를 사용하는 것이 가능하다.

 

sayHi("John");     // 에러 발생(Uncaught ReferenceError: sayHi is not defined)

let sayHi = function(name) {
  alert(`Hello, ${name}`);
};

// 함수 표현식 아래에 sayHi("John")을 적어주어야지 정상적으로 작동한다.

 

 

3️⃣ 스코프(변수에 접근할 수 있는 범위)에서 차이가 있다.

➡️ 함수 선언문

엄격 모드에서 함수 선언문이 코드 블록 내에 위치하면 해당 함수는 블록 내(함수를 감싸는 중괄호 한 쌍 내) 어디서든 접근이 가능하다.

but 블록 밖(중괄호 밖)에서는 접근이 불가하다.

 

let age = prompt("나이를 입력해 주세요.", 18);

// 조건에 따라 함수 선언
if (age < 18) {
  welcome();     // 정상적으로 실행
  function welcome() { 
    alert("안녕!");
  }
  welcome();     // 정상적으로 실행
} else {
  welcome();     // 정상적으로 실행
  function welcome() {
    alert("안녕하세요!");
  }
  welcome();     // 정상적으로 실행
}

// 중괄호 밖이기 때문에 중괄호 안에서 선언한 함수는 호출 불가!
welcome();     // Error: welcome is not defined

 

➡️ 함수 표현식

함수 표현식을 사용하면 블록 밖에서도 블록 안에서 선언된 함수 호출이 가능하다.

대신 함수 선언식 방식에서처럼 함수 선언 전에 사용하려 하면 오류가 발생한다.

 

let age = prompt("나이를 입력해 주세요.", 18);

if (age < 18) {
  // welcome(); --> 오류 발생(Uncaught ReferenceError: Cannot access 'welcome' before initialization)    
  let welcome = function() { 
    alert("안녕!");
  }
  welcome();     // 정상적으로 실행
} else {
  // welcome(); --> 오류 발생     
  let welcome = function() {
    alert("안녕하세요!");
  }
  welcome();     // 정상적으로 실행
}

// 중괄호 밖에서도 함수 호출 가능
welcome();     // 정상적으로 실행 (안녕!)

 

함수 표현식 방식을 사용할 경우 변수에 할당하여 사용하는 방식이므로 물음표 연산자(?)를 통해 위 코드를 더 단순화할 수 있다.

 

let age = prompt("나이를 입력해 주세요", 18);

let welcome = (age < 18) ? 
  function() {alert("안녕!")};
  function() {alert("안녕하세요!")};
  
welcome();

 

 

📍 어떤 방식으로 함수를 선언해야 할까?

함수 선언문을 이용해 함수를 선언하는 것이 함수 선언 전 호출이 가능하여 코드 구성이 더 자유롭고 시작이 function 지시자로 시작하여 함수를 찾는 것이 더 쉬워져 가독성이 증가한다.

따라서 함수 선언 방식을 먼저 고려하되 함수 선언 방식이 적합하지 않을 때 함수 표현식 방식을 사용하는 것이 좋다.

'Javascript study' 카테고리의 다른 글

[Javascript] 참조에 의한 객체 복사  (0) 2023.07.21
[Javascript] 객체  (0) 2023.07.21
[Javascript] 함수  (0) 2023.07.17
[Javascript] switch문  (0) 2023.07.14
[Javascript] while과 for 반복문  (0) 2023.07.14

댓글