함수 선언문, 함수 표현식 - (JavaScript)

Jiwonp·2023년 3월 2일
2

JavaScript 정리

목록 보기
5/6
post-thumbnail

2023.03.02

함수 선언문함수 표현식

function declaration, function expression 둘 모두 함수를 새롭게 정의할 때 쓰이는 방식이다. 차이점을 알아보도록 하자!

함수를 정의하는 세 가지 방식

function a () { /* ... */ }         // 함수 선언문. 함수명 a가 곧 변수명
a();	// 실행 OK

var b = function () { /* ... */ }   // (익명) 함수 표현식. 변수명 b가 곧 함수명
b();	// 실행 OK

var c = function d () { /* ... */ } // 기명 함수 표현식. 변수명 c, 함수명 d
c();	// 실행 OK
d();	// 에러!

화살표 함수(ES6)는 여기선 제외..


기명 함수 표현식은 외부에서는 함수명으로 함수를 호출할 수 없다. 오직 내부에서만 접근할 수 있다. 과거에 기명 함수 표현식은 함수명이 잘 출력됐던 반면 익명 함수 표현식은 undefined 또는 unnamed라는 값이 나왔다. 이 때문에 디버깅시 어떤 함수인지 추척하기에 익명 함수 표현식보다 유리한 측면이 있었다. 그러나 이제는 모든 브라우저들이 익명 함수 표현식의 변수명을 name 프로퍼티에 할당하고 있다. (굳이 기명 함수 표현식은 안 쓴다는 것 같다?)


함수 선언문과 함수 표현식의 실질적인 차이를 코어 자바스크립트 예제를 통해 알아보자.

예제 코드

console.log(sum(1, 2));
console.log(multiply(3, 4));

function sum (a, b) {            // 함수 선언문 sum
    return a + b;
}

var multiply = function (a, b) { // 함수 표현식 multiply
    return a * b;
}

실행 컨텍스트의 lexicalEnvironment는 두 가지 정보를 수집하는데, 여기서는 그중에서 environmentRecord의 정보 수집 과정에서 발생하는 호이스팅을 살펴보는 중이다.

예제 코드 - 호이스팅을 마친 상태

01 var sum = function sum (a, b) { // 함수 선언문은 전체를 호이스팅함
02     return a + b;
03 };
04 var multiply;                   // 변수는 선언부만 끌어올림
05 console.log(sum(1, 2));
06 console.log(multiply(3, 4));
07 
08 multiply = function (a, b) {    // 변수의 할당부는 원래 자리에 남겨둠
09     return a + b;
10 };

함수 선언문은 전체를 호이스팅한 반면 함수 표현식은 변수 선언부만 호이스팅됐다. 함수도 하나의 값으로 취급할 수 있다는 것이 바로 이런 것이다. 함수를 다른 변수에 값으로써 '할당'한 것이 곧 함수 표현식이다. 여기서 함수 선언문과 함수 표현식의 극적인 차이가 발생한다.


이제 호이스팅이 끝났으니 내부의 코드들을 차례대로 실행해 보자!

01: 메모리 공간을 확보, 확보된 공간의 주솟값을 변수 sum에 연결

04: 또 다른 메모리 공간을 확보, 그 공간의 주솟값을 변수 multiply에 연결

01(다시): sum 함수를 또 다른 메모리 공간에 저장, 그 주솟값을 앞서 선언한 변수 sum의 공간에 할당, 이로써 변수 sum은 함수 sum을 바라보는 상태가 됨

05: sum을 실행, 정상적으로 실행되어 3이 출력

06: 현재 multiply에는 값이 할당돼 있지 않음. 비어있는 대상을 함수로 여겨 실행하라고 명령한 것. 따라서 'multiply is not a function' 이라는 에러 메시지가 출력됨. 뒤의 8번째 줄은 6번째 줄의 에러로 인해 실행되지 않은 채 런타임이 종료

함수 선언문으로 작성된 sum함수는 선언 전에 호출해도 아무 문제 없이 실행된다. 초급자들이 자바스크립트를 좀 더 쉽게 접근할 수 있게 해주지만, 반대로 큰 혼란을 일으키는 원인이 되기도 한다.

함수 선언문의 위험성 (극단적 예시)

1. 개발자 A가 sum 함수를 선언 js 100번째 줄에 위치
// return x + y
2. 새로 입사한 B가 같은 파일의 5000번째 줄에서 sum 함수를 새로 선언
// return x + ' + ' + y + ' = ' + (x + y);

...
60 console.log(sum(3,4));
...
100  function sum (x, y) {		// 개발자 A의 함수
101     return x + y;
102 }
...
200  var a = sum(1, 2);
...
5000 function sum (x, y) {		// 개발자 B의 함수
5001    return x + ' + ' + y + ' = ' + (x + y);
5002 }
...
5010 var c = sum(1, 2);
5011 console.log(c);
...

A의 코드는 B가 오기 전까지는 잘 작동했을 것이다. 그러나 B가 sum함수를 다시 선언을 해버렸고 둘이 작성한 함수 선언문은 맨 위로 호이스팅이 되어서 모든 sum 함수를 B의 return 값으로 바꿔버린다.

A는 숫자 값이 나왔던 sum 함수가 갑자기 바뀌어서 당황활 것이다. 에러도 안나오기 때문이다.

만약 둘 다 함수 표현식을 사용했으면 B가 작성하기 전 까지는 A의 return 값이, 작성한 뒤에는 B값이 나왔을 것이다. 심지어 100줄 이전의 sum 함수를 호출하는 값에도 에러가 나왔을 것이다.


함수 호이스팅은 함수를 호출하기 전에 반드시 함수를 선언해야 한다는 규칙을 무시한다. 함수 선언문 대신 함수 표현식을 사용할 것을 권장한다고 한다!

profile
매일 풀타임 코딩

2개의 댓글

comment-user-thumbnail
2023년 3월 2일

함수표현식 작성을 습관화하도록 해봐야겠네요!

1개의 답글