JS에서는 함수 선언문보다는 함수 표현식을 더 권장한다. 그 이유는 무엇일까?
먼저 함수 선언문과 함수 표현식에 대해 알아보자
// 함수 선언문
function a () {
console.log("hello world");
}
// 익명 함수 표현식
var b = function () {
console.log("hello world");
}
Javascript라는 언어는 코드가 실행할 때 ‘호이스팅’이 발생한다.
호이스팅을 하게 되면 함수 선언문은 전체를 호이스팅을 하게되고 함수 표현식은 선언부만 끌어 올리게 된다.
함수 선언문과 함수 표현식
-
코드 예시
// 함수 선언문, 함수명 a가 곧 변수명 function a() { /* .... */ } a(); // 실행 OK // 익명 함수 표현식, 변수 b가 곧 함수명 var b = function () { /* ... */ } b(); // 실행 OK // 기명 함수 표현식, 변수명은 c 함수명은 d var c = function d() { /* ... */ } c(); // 실행 OK d(); // 실행 NO
🆙 function d() 가 실행이 안되는 이유는?
외부에서는 함수명을 함수를 호출할 수 없다. 현재 함수 d는 함수 c안에 있다. 과거에는 기명 함수 표현식은 함수명이 잘 출력 됐던 반면 익명함수 표현식은 undefined 또는 unnamed라는 값이 나왔었다. 이 때문에 기명 함수 표현식이 디버깅 시 어떤 함수인지를 추적하기에 익명 함수 표현식보다 유리한 측면이 있었다. 그러나 이제는 모든 브라우저들이 익명 함수 표현식의 변수명을 함수의 name 프로퍼티에 할당하고 있다. 한편 c() 함수 내부에서 c()로 호출하든 d()로 호출하든 잘 실행 된다. 따라서 함수 내부에서 재귀함수를 호출하는 용도로 함수명을 쓸 수 있다. 다만 c()로 호출해도 되는 상황에서 굳이 d()로 호출해야할 필요가 있을지는 의문이다.
함수 선언문과 함수 표현식의 실질적인 차이 😇
-
원본코드
console.log(sum(1, 2)); console.log(multiply(3, 4)); // 함수 선언문 sum function sum (a, b) { return a + b ; } // 익명 함수 표현식 multiply var multiply = function (a, b) { return a + b; }
실행컨텍스트의 렉시컬 환경은 두 가지 정보를 수집하는데, 여기서는 그중에서 ER의 정보 수집 과정에서 발생하는 호이스팅을 살펴보자
-
호이스팅을 다 마친 상태
// 함수 선언문은 전체를 호이스팅 한다. function sum(a, b) { return a + b; } // 변수는 선언부만 끌어올린다. var multiply; console.log(sum(1, 2)); // OK console.log(multiply(3, 4)); // NO ❌ // 변수의 할당부는 원래 자리에 남게된다. multiply = function (a, b) { return a + b; }
함수도 하나의 값으로 취급할 수 있다는 것이 바로 이런 것이다. 함수를 다른 변수에 값으로써 할당한 것이 곧 함수 표현식이다.
-
에러메세지
TypeError: multiply is not a function
하지만 우리는 왜 함수 표현식이 이렇게 에러가 발생함에도 불구하고 왜 함수 표현식을 더 권장하는걸까? 🧐🧐
얼핏 보면 함수 선언식이 에러도 나지 않고 선언하기 전에도 사용할 수 있기 때문에 편해보이지만 코드를 한번 자세히 살펴보면 이상한 점이 존재한다.
함수 표현식을 더 권장하는 이유는 🌟 함수 표현식은 선언 전 함수 사용을 막을 수 있다 🌟
-
함수 선언식을 사용하여 짠 코드
[상황] 과거의 나는 열심히 sum 함수를 구현하였다. 하지만 새로온 신입이 나의 sum 함수를 발견하지 못하고 새롭게 sum 함수를 짜게 됐다. 이 상황에서 에러가 발생하는 것은 바로 나의 코드이다.
// 과거의 내가 짠 코드 console.log(sum(1, 3)); function sum (a, b) { return a + b; } //... 500 번재 줄 // 새로운 신입의 코드 function sum (a, b) { return a + '+' + b + '=' + (a + b); } console.log(sum(2,3)); //1+3=4 //2+3=5
그 이유는 함수 선언문 전체가 호이스팅 되어 나의 코드가 덮어 씌우기가 되버렸다. 😱 물론 극단적인 상황이지만 함수 표현식은 이러한 상황을 막아준다.
-
함수 표현식을 사용하자
console.log(sum(1, 2)); // error var sum = function (a, b) { return a + b; } //... 5000번째 var sum = function (a, b) { return a + '+' + b + '=' + (a + b); } var c = sum(3, 4); console.log(c);
더 나아가 var 대신 const를 사용하면 호이스팅때문에 발생하는 에러를 막아준다는 글을 많이 보았을 것이다.
-
var의 변수 선언
var name; name = 'nibble';
-
const의 변수선언
const name; //error!!!!!
결론 🔥
const 변수 선언은 변수의 정의와 초기화가 한거번에 이루어지기 때문에 위같은 상황들을 막을 수 있다. const로 할당한 함수 표현식을 사용하자!
Reference
- 코어자바스크립트