본문 바로가기

자스핑

[week 01] javascript의 다양한 함수 선언 방식을 알아보자

javascript의 다양한 함수 선언 방식

javascript에는 여러 가지 방법으로 함수를 선언할 수 있습니다. 이렇게 다양한 방식이 왜 존재하고 그들간의 차이점에 궁금증이 생겨서 함수 선언문, 함수 표현식, 익명 및 기명 함수 표현식 그리고 화살표 함수에 대해 알아보고자 합니다!!


1. 함수 선언문

함수 선언문은 function 키워들 통해 선언되며 이름을 반드시 포함해야 합니다. 함수 선언문은 호이스팅되어 코드의 최상단으로 끌어올려지므로 함수가 정의되기 전에 호출이 가능합니다.

 

자바스크립트 엔진은 함수 선언문을 해석해서 함수 객체를 생성하게 됩니다. 이때 함수의 이름은 함수 몸체 내부에서만 유효한 식별자이기 때문에 외부에서 함수 이름에 대한 참조가 불가능합니다. 하지만 외부에서 함수 이름에 대한 참조가 가능한 이유는 자바스크립트 엔진이 암묵적으로 함수 이름과 동일한 이름의 식별자를 생성하고 그곳에 함수 객체를 할당하기 때문입니다.

function greet() { // 반드시 이름을 포함해서 선언해야 한다.
  console.log("Hello!");
}
greet(); // "Hello!"

var greet = function greet() { // 자바스크립트 엔진이 암묵적으로 식별자를 생성했다고 생각하고 코드를 짜면 이와 같다.
  console.log("Hello!");
}
greet(); // "Hello!"

그래서 함수 선언문은 함수 이름인 add가 호출이 된 것이 아닌 식별자 add로 호출된 것입니다.

함수 선언문의 장단점

장점

  • 호이스팅 덕분에 함수가 정의된 위치와 관계없이 호출할 수 있어 코드 구조가 자유롭다.

단점

  • 함수가 전역으로 호이스팅될 경우 같은 이름의 함수를 중복 선언될 가능성이 있어 이름 충돌이 날 수 있다.
  • 호출 시점과 정의 시점의 혼동이 발생할 수 있어 코드의 가독성이 떨어질 수 있다.

2. 함수 표현식

함수 표현식은 함수를 변수에 할당하는 방식으로 함수 자체가 변수에 담기게 됩니다. 함수 표현식은 호이스팅되지 않으므로 정의된 후에만 호출할 수 있습니다.

const greet = function() {
  console.log("Hello!");
};
greet(); // "Hello!"

앞에 보았던 함수 선언문에 자바스크립트 엔진이 암묵적으로 동작하는 코드와 비슷하게 생긴것을 알 수 있습니다. 결론적으로 자바스크립트 엔진은 함수 선언문을 함수 표현식으로 변환해 함수 객체를 생성한다고 볼 수 있습니다.

이러한 함수표현식은 일급 객체처럼 동작합니다.

  • 일급 객체 : 힘럼 자유롭게 사용할 수 있다는 의미

함수 표현식이 호이스팅 되지 않는 이유

함수 표현식은 변수 선언문 + 변수 할당문을 한 번에 기술한 축약 표현이기 때문에 변수 선언만 끌어올려가고 함수를 변수에 할당하는 작업은 해당 코드가 실행되는 시점에 할당됩니다. 그래서 그 전에 사용한다면 undefined를 호출하는 것이기 때문에 타입 에러가 뜨게 됩니다.

 

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

함수 표현식의 장단점

장점

  • 함수 선언이 코드의 흐름에 맞게 위치하므로 가독성이 좋다.
  • 필요한 시점에서 함수가 정의되므로 불필요한 전역 함수 선언을 줄일 수 있다.

단점

  • 호이스팅되지 않기 때문에 코드 상에서 함수가 정의되기 전에 호출하면 오류가 발생한다.

2.1 익명 함수 표현식과 기명 함수 표현식

함수 표현식에는 익명 함수 표현식과 기명 함수 표현식이 있습니다.

익명 함수 표현식

함수 이름이 지정되지 않은(이름을 생략한) 함수 표현식으로 함수 이름 추론에 의존하여 호출 스택에서 이름을 확인할 수 있습니다.

const greet = function() {
  console.log("Hello!");
};

console.log(greet.name) // 함수 이름 추론에 의해 이름 추론 가능

기명 함수 표현식

명시적으로 함수 이름을 지정한 함수 표현식으로 내부에서 재귀 호출이 가능하며 호출 스택에서 이름을 정확히 확인할 수 있습니다.

airbnb javacript 스타일 가이드에서는 기명 함수 표현식을 사용할 것을 권장하고 있습니다.

( 하지만 이 내용은 2021년 12월에 릴리즈 된 내용이며 현시점에는 함수 이름 추론이 안되는 IE는 공식적으로 지원이 중단되었기 때문에 화살표 함수를 사용해도 괜찮을 것 같다는 의견도 다수 존재합니다!)

const factorial = function fact(n) {
  return n <= 1 ? 1 : n * fact(n - 1);
};

이름 추론과 한계

자바스크립트 엔진은 변수 이름을 기반으로 함수의 이름을 추론할 수 있지만 모든 경우에 정확히 이름이 추론되지는 않습니다. 특히 콜백 함수나 여러 단계를 거쳐 전달된 함수는 익명(anonymous)로 표시되거나 호출 스택에서 이름이 생략될 수 있다고 합니다. 

 


3. 화살표 함수

화살표 함수는 => 키워드를 사용해 좀 더 간략한 방법으로 함수를 선언할 수 있습니다. 또한 화살표 함수는 항상 익명 함수로 정의합니다. 표현만 간략한 것이 아니라 내부 동작 또한 간략화되어 있습니다.

화살표 함수는 함수 표현식의 일종이기 때문에 함수 표현식과 같은 이유로 호이스팅이 일어나지 않습니다. 또한 익명 함수지만 함수 이름 추론에 의해서 호출 스택에 추론된 이름으로 표시됩니다.

화살표 함수와 일반 함수의 차이점

화살표 함수는 인스턴스를 생성할 수 없습니다. 즉 new 키워드를 통해서 객체를 생성하는 생성자 함수로 사용할 수 없다는 의미입니다. 일반 함수의 경우 new키워드를 사용하여 호출하면 해당 함수가 생성자 함수로 동작하면서 새로운 객체(인스턴스)를 반환하지만 화살표 함수는 이러한 방식의 사용이 불가합니다.

const Person = (name) => { // 화살표 함수는 인스턴스를 생성할 수 없다.
  this.name = name;
};
const person = new Person("seonghui"); // TypeError: Person is not a constructor

const Person = function(name) { // 함수 표현식으로 선언할 경우 인스턴스 생성 가능
  this.name = name;
};
const person = new Person("seonghui");

함수의 this가 자동으로 상위 스코프의 this에 바인딩됩니다. 

화살표 함수의 장단점

장점

  • this를 자동으로 상위 스코프에 바인딩하므로 객체 메서드나 콜백 함수로 사용 시 편리하다.
  • 문법이 간결하여 코드의 가독성이 높아진다.

단점

  • this가 상위 스코프를 참조하므로 일반 함수처럼 this가 필요할 경우 적합하지 않습니다.
  • 자체적인 arguments 객체가 없어 arguments가 필요할 때는 사용할 수 없다.

마치며

javascript의 다양한 함수 선언 방식은 코드 작성의 유연성과 효율성을 높여 줍니다. 함수 선언문, 함수 표현식, 화살표 함수 등의 방식은 각각의 특징과 장단점을 지니고 있으며 상황에 따라 적절한 선택이 필요하다는 생각을 하게 되었습니다. 함수 선언 방식의 차이를 이해하면 코드의 구조와 가독성을 개선할 수 있고 예상하지 못한 오류를 예방하는 데에도 도움이 될 것이라 생각합니다. 각 방식의 특성을 잘 활용하여 코드의 유지보수성과 안정성을 높여봅시다 !!