자바스크립트에서는 `function`이 없다고 생각하기

J·2025년 6월 24일
post-thumbnail

요약

  1. 자바스크립트의 함수 선언문은 문제가 있다.
  2. 생성자 선언은 class로 대체가 가능하다.
  3. function 에약어를 안 쓰기 위해 모든 함수는 화살표 함수로 정의한다.
  4. 다만 메소드를 정의할 땐 this binding이 필요하기에, 이 때는 메소드 축약형으로 함수를 작성한다.

function은 문제가 있다

자바스크립트에서는 function으로 할 수 있는 게 굉장히 많다. 그리고 한 예약어로 할 수 있는 게 많다는 것은 헷갈린다고도 할 수 있겠다.

function foo() {}

(관점에 따른) 장점
함수 선언문으로 정의된 함수는 호이스팅이 된다. 호이스팅이란 선언이 해당 스코프의 최상단으로 끌어올려지는 현상이다. 이 덕분에 함수를 호출한 이후에 함수가 정의해도 문제가 없다. 이는 top-down 관점으로 코드를 작성하게 해준다.

// when you open this file, these get run
subFunctionA()
subFunctionB()
subFunctionC()

// detail
function subFunctionA() {}
function subFunctionB() {}
function subFunctionC() {}

문제점
그러나 위의 장점은 개인의 코딩 스타일에 자율성을 주는 수준인 반면, 단점은 치명적이다. 자바스크립트에서 함수 선언문은 재정의가 가능하다.

// 문제 상황 예시
function calculatePrice(base) {
  return base * 1.1; // 10% 마진
}

// 100줄 후...
function calculatePrice(base) {
  return base * 1.2; // 20% 마진으로 변경하려다가...
}

// 어느 함수가 실행될까? 디버깅이 어려워진다.

해결책: 함수 표현식
ES6에서 const, let이 소개되며 이에 대한 해결책이 의도치 않게 나왔다.

const foo = funtion () {}
함수를 변수에 할당하면 const, let에 따라 재정의가 안 된다. 실수를 할 여지를 더 줄이게 되었다.

여기에 화살표 함수까지 사용을 하면 function은 아예 안 쓸 수가 있게 된다.
const foo = () => {}
문제였던 함수 선언문의 흔적은 더 이상 보이지 않는다.

생성자 함수, 이것도 함수야?

자바스크립트에서는 객체의 기본이 되는 형태를 생성자 함수로 만들 수 있다.

function User(name, age) {
  this.name = name;
  this.age = age;
}

하지만 ES6에서 도입된 class 문법이 더 명확하고 직관적이다. 함수를 정의할 때는 function을 안 쓰겠다고 했는데, 객체 생성을 위해서만 function을 쓰는 것도 일관성이 떨어진다.

class User {
	constructor(name, age) {
		this.name = name;
		this.age = age;
  }
}

이로써 funcion 키워드 없이 객체를 생성할 수 있다.

메소드 정의에는 화살표 함수가 적절치 않다

객체의 메소드에서는 this가 중요하다. 하지만 화살표 함수는 자신만의 this를 만들지 않는다.

const user = {
  name: "김철수",
  
  // ❌ 화살표 함수 - this가 user를 가리키지 않음
  introduceArrow: () => {
    return `안녕하세요, 저는 ${this.name}입니다.`;
    // this.name과 this.age는 undefined
  },
  
  // ✅ 일반 함수 표현식 - this가 user를 가리킴
  introduceFunction: function() {
    return `안녕하세요, 저는 ${this.name}입니다.`;
  }
};

console.log(user.introduceArrow());   
// "안녕하세요, 저는 undefined입니다."

console.log(user.introduceFunction());
// "안녕하세요, 저는 김철수입니다."

그러나 우리는 function 키워드가 싫다. 메소드에서는 축약형을 쓰면 선언문을 function 키워드 없이 쓸 수 있다.

const user = {
  // ...
  
  // ⚠️ 일반 함수 - function 키워드 필요
  introduceFunction: function() {
    return `안녕하세요, 저는 ${this.name}입니다.`;
  }
  
  // ✅ 메소드 축약형 - function 예약어 불필요
  introduceMethod() {
    return `안녕하세요, 저는 ${this.name}입니다.`;
  },
    
  // ...

여담: function을 안 쓴다면 함수 호이스팅은 쓸 수 없다

function 예약어를 쓰는 상황엔 여러 문제가 있기에 이를 사용하지 않고 코드를 작성하는 방법에 대해 논의했다.

다만, const, let은 호이스팅을 체감할 수 없기에 이렇게 함수를 작성하면 (메소드를 작성할 땔 제외하곤) 함수 호이스팅을 포기해야 하며, top-down 방식의 코드 작성도 마찬가지로 포기해야 한다.

자바스크립트에서는 down-top 스타일로 작성하는 게 관례로 자리잡힌 것은 top-down의 명료함보다도 함수 표현식의 안전함의 가치가 더 높다는 방증일 것이다.

0개의 댓글