.
본문 바로가기
JavaScript

함수 선언식 vs 함수 표현식

by 와칸다개발자 2021. 12. 20.

둘의 차이는 정확히 뭘까????

 


console.log(add(2,3));
console.log(sub(12,3)); 	// Variable 'sub' is used before being assigned

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

const sub = function(a:number, b:number){
    return a - b;
}

 

함수 선언문은 선언이전에 호출할 수 있고 표현식은 이전에 호출할 수 없다.

 

이러한 이유는 선언문과 표현식이 함수의 생성시점이 다르기 때문이다.

 

선언문

 

선언문은 자바스크립트가 실행되고 있는 시점인 런타임 이전에 자바스크립트 엔진에 의해

 

먼저 실행된다. 즉 이말은 함수 선언문은 런타임 이전 함수 객체가 먼저 생성이 된다.

 

JS엔진은 함수 이름과 동일한 이름의 식별자를 생성하고 할당한다.

 

런타임시점에 이미 함수 객체가 생성되고 할당되어 있다. 그러므로 선언문 이전에 함수를 참조할 수 있다.

 

함수 선언문이 코드 가장 윗부분에 끌어 올려진 것처럼 동작하는 특징을 호이스팅이라 한다.

 

가장 윗부분으로 끌어 올리기 때문에 위 코드는 다음과 같다.

 

// 호이스팅에 영향으로 가장 윗부분으로 끌어 올려짐
function add(a:number, b:number){
    return a + b;
}

console.log(add(2,3));
console.log(sub(12,3)); 	// Variable 'sub' is used before being assigned

const sub = function(a:number, b:number){
    return a - b;
}

 

함수호이스팅, 변수호이스팅

 

먼저 함수 표현식을 알아보기 전에 이 두개를 알아보자.

 

var키워드 변수 선언문과 함수 선언문은 런타임 이전 엔진이 먼저 실행시켜 식별자를 생성한다는 점에서

 

동일하다. 그러나 변수 선언문은 undefined로 초기화되며, 함수 선언문을 통해 생성된 식별자는 함수 객체로 

 

초기화된다. 그러므로 변수선언문은 선언문 이전에 호출할 시 undeifned값을 뱉어내지만

 

함수 선언문으로 정의한 함수를 선언문 이전에 호출하면 함수 호이스팅에 의해 호출이 가능하다.

 

console.log(variable);	// undefined

var variable;

 

표현식

 

함수 표현식은 변수에 할당되는 값이 함수 리터럴인 것이다. 

 

변수 선언은 런타임 이전에 실행되 undefined로 초기화되지만 

 

변수 할당문의 값은 할당문이 실행되는 시점, 즉 런타임 시점에서 평가하므로 

 

함수 표현식은 할당 문이 실행되는 시점(런타임 시점)에 함수 객체가 된다.

 

따라서 함수 표현식은 변수 호이스팅이 발생한다.

 

함수 표현식은 반드시 함수 표현식 이후에 참조 및 호출을 해야 한다.

 

 

자바스크립트 DeepDive

 

함수 호이스팅은 런타임 이전에 객체를 생성하고 할당하기 때문에 호출하기 전 선언해야 한다는 

 

규칙을 무시하게 된다.

 

표현식은 왜 쓰는걸까?

 

표현식은 대표적으로 클로져, 콜백함수의 사용용도를 가진다.

다음의 코드는 표현식의 사용이유에서 자주 사용되는 예제이다.

다음과 같이 ES6가 나오기 전 var 키워드만 사용할 수 있다고 가정해보자.

 

<div id="root">
  <div class="list">000</div>
  <div class="list">111</div>
  <div class="list">222</div>
  <div class="list">333</div>
</div>

 


var list = document.querySelectorAll(".list");

function clickEvent() {
  console.log(index);
}

for (var index = 0; index < list.length; index++) {
  list[index].addEventListener("click", clickEvent);
}

// 4
// 4
// 4
// 4

 

반복문 변수 키워드는 i는 함수레벨 스코프의 영향을 받는 var로 선언했다.

블록레벨 스코프인 let을 사용하면 위 예제가 의미없다.

 

위 코드는 list 클래스명을 가진 태그에 클릭 이벤트를 추가하는 코드이다.

 

클릭이벤트의 콜백함수는 비동기로 작동하므로 clickEvent()함수 내부에 index는 

 

반복문을 다 돌고 난 후 값인 4를 참조하게 된다. 이는 클로저를 통해 값을 기억하고 사용할 수 있다.

 

클로저는 간단하게 자신이 실행된 환경을 기억하는 것이다. (너무 중요하므로 나중에 다뤄야징)

 


var list = document.querySelectorAll(".list");

function clickEvent(i) {
  function inner() {
    console.log(i);
  }

  return inner;
}

for (var index = 0; index < list.length; index++) {
  list[index].addEventListener("click", clickEvent(index));
}

// 1
// 2
// 3
// 4

 

내부 inner함수는 클로저의 특징으로 i를 기억하고 함수를 반환한다. 

 

다음과 같이 즉시실행함수를 사용해도 된다. 

 

var list = document.querySelectorAll(".list");

for (var index = 0; index < list.length; index++) {
  (function (i) {
    list[i].addEventListener("click", function () {
      console.log(i);
    });
  })(index);
}

// 1
// 2
// 3
// 4

'JavaScript' 카테고리의 다른 글

Syntax Sugar 정리  (0) 2022.04.20
이벤트 버블링, 캡쳐링, 위임  (0) 2022.03.11
화살표함수는 왜 사용하는걸까?  (0) 2021.12.22
let, const 블록레벨 스코프  (0) 2021.10.09

댓글