자바스크립트에서 함수를 정의하는 방법은 총 세 가지가 있다.
- 함수 선언식 function declaration
- 함수 표현식 function expression
- 화살표 함수 arrow function
화살표 함수는 간편하게 쓸 수 있는 모양새부터 다른 두 함수 정의 방식과 아주 다르고, 함수 내부에서 this가 생성되지 않는 등 나머지 두 가지 함수 정의 방법과 다른 부분을 알겠지만, 반면 선언식과 표현식은 생김새가 너무 유사해서 대체 무슨 차이가 있어서 이 둘을 구분하는 건지 궁금했다. syntax의 미세한 차이 말고 기능적 차이가 분명 있을텐데. 그렇지 않고서야 굳이 함수를 정의하는 방법을 따로 두 가지를 만들어 놓을 이유가 없을 테니 말이다.
함수 선언식 syntax:
function foo (arg1, arg2, ..., argN) {
// 실행할 코드
}
함수 표현식 syntax:
const foo = function (arg1, arg2, ..., argN) {
// 실행할 코드
}
이것 좀 보소. 표현식에 const 라는 변수 선언 키워드 하나 들어간 거 말고 대체 무슨 차이냐고... 선언식에서 변수 선언 키워드를 쓰지 않았어도 이후에 똑같이 함수명(이 경우에 foo)으로 함수 호출해서 쓸 수 있는데 말이지🤔
그러다 함수 결과값을 새로운 변수에 담는 코플릿(코딩 테스트) 문제를 마주하면서 새로운 의문이 생겼다. 함수를 정의한 코드보다 먼저, 그러니까 그 윗줄에서 함수를 호출해도 작동할까?
왜인지는 몰라도 함수 표현식보다 선언식을 쓰는 경우가 더 많다. 보통 코딩 테스트의 솔루션 코드 자체가 선언식으로 정의되어 있다(이건 솔루션 함수 자체가 테스트이니 그 함수를 따로 변수 선언을 해줄 필요가 없는 거겠지). 선언식으로 함수를 정의한 코드 윗줄에서 함수를 불러와도, 그 아래에서 불러와도 함수는 똑같이 호출되고 결과값을 반환했다. 그-런-데 똑같은 함수를 표현식으로 바꾸니 함수를 정의한 부분보다 윗줄에서 함수 호출을 시도하려 하자 ReferenceError가 뜨면서 해당 함수가 정의되지 않았다고 한다...!
찾아보니 이것은 호이스팅hoisting에 따른 차이였다. 변수나 함수의 선언(정의)과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮기는 작업을 호이스팅이라고 하는데, 함수 선언식은 호이스팅이 적용되고, 함수 표현식은 호이스팅이 적용되지 않는 것이다. 다시 말해 함수 선언식으로 함수를 정의한 경우, 브라우저가 자바스크립트를 해석할 때 해당 함수를 맨위로 끌어올린다.
그렇기 때문에 함수 선언식으로 정의한 경우 함수를 정의한 위치와 상관없이 앞뒤 어디에서나 함수를 호출해도 에러가 뜨지 않는 것이고, 표현식은 함수를 정의한 이후에만 함수를 호출할 수 있다.
함수를 정의하는 두 방식의 차이와 함수 정의와 호출의 위치에 따른 차이라는 사뭇 다른 줄 알았던 두 가지 문제가 호이스팅이라는 하나의 키워드를 관통하는 한 가지 문제로 수렴하는 순간이었다. (내적 희열🥸)
하지만 아직 명확히 해결되지 않은 의문이 한 가지가 남아있다.
변수의 경우 호이스팅이 발생하지 않는 let, const 키워드를 권장하고 var의 사용은 지양한다.
💡 그런데 함수는 어째서 호이스팅 여부와 상관없이 선언식과 표현식을 둘 다 쓰는 걸까?
위의 질문은 미래의 내가 답변할 수 있을 것이라 믿으며... 그 미래가 근미래이길 바라봅니다.
참고자료:
'배워서 남 주자' 카테고리의 다른 글
배열 reduce 메소드 - array.reduce() (0) | 2022.11.08 |
---|---|
변수, 선언, 할당, 메모리 그게 다 뭔데? (부제: 원시자료형과 참조자료형의 차이) (1) | 2022.11.07 |
배열과 객체 순회 (0) | 2022.11.06 |
배열의 오름차순 정렬과 버스정류장 도착정보표시 (2) | 2022.10.19 |
JavaScript의 치명적 버그 (4) | 2022.10.08 |