본문 바로가기
FE/Javascript

함수 선언식, 표현식, 화살표 함수의 공통점과 차이점

by ideal_string 2022. 8. 14.

자바스크립트를 배우면 제일 먼저 맞딱뜨리는 것이 함수고, 제일 많이 쓰는 것이 함수다. 함수를 쓰는데 있어서 세 가지 방법이 있다. 함수 선언식, 함수 표현식, 화살표 함수. 함수 선언식은 전통적인 함수 선언 방법이고, 화살표 함수는 자바스크립트가 ES6로 업데이트되면서 새로 생긴 방식이다. 세 함수식 특징을 잘 알고 사용할 필요가 있기에 이들의 공통점과 차이점을 살펴보려 한다.

 

먼저 각 선언식이다.

 

함수 선언식

함수의 기본 선언식이다. function을 선언하고 함수명('func_declaration')을 기재하고 매개변수를 위한 소괄호와 로직을 위한 중괄호를 쓴다.

function func_declaration(){
	console("함수 선언식")
}

 

함수 표현식

비슷한 듯 다른 함수 표현식. 변수를 선언하듯 자료형과 함수명('func_expression')을 기재하고 함수를 표현한다.

const func_expression = function(){
	console.log("함수 표현식")
};

 

화살표 함수

화살표 함수식은 귀찮은 개발자, 혹은 빠른 코딩을 위해 기존 표현식 함수에서 업그레이드된 듯한 모습이다. 함수 표현식에서 'function'이란 글자를 빼고 매개변수를 위한 소괄호 다음에 '=>' 화살표를 넣고 로직을 위한 중괄호를 쓴다.

const arrow_func = () => {
	console.log("화살표 함수")
};

세 함수 방식의 공통점

1.  중괄호 안 로직을 수행한다.

세 함수 방식의 차이점

1. 세미콜론 유무 -> 함수 표현식과 화살표 함수는 변수와 같이 작성하기 때문에 끝에 세미콜론이 붙는다.

2. 함수 이름(익명) 유무 -> 함수 선언식은 익명 불가, 함수 표현식과 화살표 함수는 익명 가능.

3. 호이스팅 유무 -> 함수 선언식은 호이스팅 됨, 함수 표현식과 화살표 함수는 호이스팅되지 않음.

4. this 바인딩 유무 -> 화살표 함수는 자체 this가 없고, 상위 스코프를 찾아간다.

5. arguments 유무 -> 화살표 함수는 arguments가 없다.

 

함수 만드는 세 가지 공통점은 로직을 실행한다는 점 하나다. 기본 작동 방식 외 나머지는 꽤나 다르다. 화살표 함수는 함수 선언식의 단축 표현이다. 먼저 함수 선언식과 함수 표현식의 차이점을 살펴본 후 화살표 함수 특징을 보고자 한다.

 

함수 선언식과 표현식의 차이점

  • 함수 선언식은 호이스팅되지만, 함수 표현식은 호이스팅되지 않는다. 즉, 선언식은 구현 위치에 상관 없이 호출할 수 있지만, 표현식은 그렇지 않다.
  • 함수 표현식은 구현된 후 사용할 수 있고, 함수 선언식은 전체 스크립트가 분석 될때까지 기다려야 한다.
  • 함수 표현식은 다른 함수에 대한 인수로 사용할 수 있지만, 함수 선언식은 불가능하다.
  • 함수 표현식은 익명으로 사용할 수 있으나, 함수 선언식은 함수 이름이 필수다.

함수 선언식과 표현식 모두 어느 것이 무조건 좋다 나쁘다로 결정지을 수 없다. 상황에 따라 함수 선언식이 좋을 수 있고, 함수 표현식이 좋을 수도 있다.

# 함수 선언식을 사용하기가 더 좋은 경우

  1. 함수가 길거나 다른 위치에서 사용해야 할 때 -> 더 읽기 쉽고 이해하기가 빠르기 때문.
  2. 실명 함수가 꼭 필요할 때
  3. 재귀 함수를 만들 때
  4. 함수가 정의 되기 전에 다른 부분을 미리 로드해야할 때

# 함수 표현식을 사용하기가 더 좋은 경우

  1. 호이스팅이 되지 않아야 할 때
  2. 익명 함수로 사용하고 싶을 때
  3. 다른 함수의 인수로 사용하고 싶을 때(클로져)
  4. 즉시 호출함수 표현식(IIFE)과 같이 함수 실행 시기를 제어하고 싶을 때

화살표 함수 특징

화살표 함수는 위에서 언급한 대로 ES6에서 새로 나왔고, 매우 간결하게 쓸 수도 있는 함수 방식이다.

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

a, b 매개변수를 받아 더하고 리턴하는 함수 선언식을 화살표 함수로 바꾸면 아래와 같다.

const adder = (a, b) => a+b;

functions이란 글자를 타이핑하지 않고도 함수 사용할 수 있고, return이 한줄이라면 중괄호와 return 글자까지도 쓰지 않고 함수를 쓸 수 있다. 함수 표현식과 비교해도 훨씬 간편하다. 화살표 함수는 아래 처럼 기명 함수가 굳이 필요 없을 때 자주 사용한다.

setInterval(()=>{console.log("1초가 지났습니다.")},1000)

다만, 간편함 속에는 기존 함수와 다른 특징이 숨어 있음을 인지할 필요가 있다. 화살표 함수는 위에서 언급한 함수 이름 없이 쓸 수 있다는 '익명' 이외에 'this'와 'arguments'도 없다.

 

# 화살표 함수에서 this

아래는 함수 표현식으로 사용했을 때다. (https://codepen.io/idealstring/pen/poLxydZ)

함수 안에 함수를 사용했을 때, 함수 표현식

객체 안에 counter와 setCounter 함수를 만들어 넣었다. setCounter 함수는 표현식으로 작성했다. 함수 안에는 this.counter를 출력하고, button을 누르면 this를 출력하게 했다.

 

함수 표현식은 자체 this를 가지고 있기 때문에 setCounter에서 this를 사용할 경우 상위 함수에 있던 counter값이 아닌, 자체 스코프 안에 있는 button 태그를 값으로 가져왔다. couter 값을 출력하기 위해 setCounter에 bind를 걸었다. 바인딩 하니 상위 스코프에 있는 this, 즉 counter 값을 출력했다.

 

그러나, 화살표 함수는 this가 없다. 위와 같은 상황이라면 화살표 함수는 this를 굳이 바인딩 걸지 않더라도 바로 상위 스코프에 에서 this를 찾는다. (https://codepen.io/idealstring/pen/GRxYZPE)

함수 안에 함수를 사용했을 때, 화살표 함수.

화살표 함수를 쓴 결과다. 별다른 바인딩 처리하지 않았음에도 상위 스코프에 있는 counter을 this로 인식했다. 화살표 함수에는 this가 없음을 확인할 수 있다. 더불어 this가 없기에 class 생성자 함수로 쓸 수 없다(https://codepen.io/idealstring/pen/gOeBrNX).

화살표 함수는 constructor로 사용할 수 없음을 보여주는 테스트.

# 화살표 함수에서 arguments

화살표 함수에는 없는 게 하나 더 있다. 바로 arguments. 함수 선언식이나 표현식을 사용할 경우 함수에서 매개 변수를 특별히 지정하지 않아도 arguments를 통해 유사배열로 매개 변수에 접근할 수 있는데 반해 화살표 함수는 arguments가 없다(https://codepen.io/idealstring/pen/eYMPzJO).

화살표 함수에서 호출한 arguments 상태
함수 표현식에서 호출한 arguments 상태

간략히 보는 함수식 차이

  함수 선언식 함수 표현식 화살표 함수
함수 이름 필수 선택 선택
호이스팅 가능 불가 불가
this 가능 가능 없음(상위 스코프 찾음).
arguments 있음 있음 없음(상위 스코프 찾음).

 

결론

각 함수 선언 방식은 각자 나름대로의 장점을 가지고 있다. 다만, 상대적으로 함수 표현식과 화살표 함수가 사용성에서 유연함이 높다. 유연함 속에서도 함수 표현식과 화살표 함수는 this와 arguments에서 분명한 차이가 있기 때문에 조심할 필요도 있다. 함수를 선언할 때 무턱대고 선언부터 하는 게 아니라, 현재 만드는 기능이 어떻게 움직이는 지 명확하게 인지하고 어떤 함수가 좋을 지 먼저 생각하고 코딩을 시작하는 게 좋을 듯하다.

※ 잘못된 내용이 있을 경우 댓글로 알려주세요. 배우고 익히고 수정하겠습니다:)

'FE > Javascript' 카테고리의 다른 글

try & catch  (0) 2022.09.06
async & await  (0) 2022.09.05
REST-API vs GraphQL-API  (0) 2022.09.02
Template literals  (0) 2022.08.31
'getElementById' VS 'querySelector'  (0) 2022.08.08