function 키워드에 대해

세바님·2024년 5월 3일
2
post-thumbnail

여러분은 function 키워드를 자주 쓰시나요? 저의 경우 일반적으로는 지향하는 편이었습니다. 이유는 딱히 없습니다. 이전에는 function 키워드로 함수 정의를 더 많이 했던 것 같은데 가면 갈수록 화살표 함수를 쓰게 되더라구요.
저번에는 친구들 사이에서 이에 대해 얘기를 했던 적도 있습니다. 아무래도 취향의 영역이 강한 것 같아요.

이 글에서는 function 키워드에 대해 자세히 알아볼 것입니다.

function 키워드의 역할

먼저 function 키워드가 뭘 하는지 부터 생각해 봅시다. 뭐, 당연히 '함수'를 만드는거겠죠. 좀 더 정확히 짚어 봅시다.

function 키워드는 다음과 같이 사용될 수 있습니다.

  • 일반 함수
  • 객체의 메서드
  • 생성자 함수
  • 제네레이터 함수

역시 예전부터 존재하던 틀딱 문법이라 그런지 키워드 하나의 역할 치곤 꽤 많습니다. (아마도)

그로 인한 문제점

그리고 틀딱 문법이라서 생기는 문제점도 많습니다.

일반 함수

먼저 function 키워드로 정의한 함수와 화살표 함수를 콘솔에 찍어 비교해 봅시다.

function a() {}
console.dir(a)

const b = () => {}
console.dir(b)


우리가 일반 함수로서 사용을 목적으로 선언을 했는데, 그 안에 들어있는 prototypethis 를 쓸 일이 있을까요?

또, arguments와 caller 부분을 봅시다. 이를 각각 일반 함수와 화살표 함수에서 출력을 해 보면 일반 함수는 값을 반환하고, 화살표 함수는 오류를 발생시킵니다.

console.log(a.arguments) // null
console.log(a.caller) // null

console.log(b.arguments) // Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
console.log(b.caller) // Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them

MDN 웹 독스를 보니 이는 deprecated 되었고, 보안 문제와 관련이 있다고 합니다. 링크

생성자 함수

다음으로 생성자 함수로 사용할 경우를 보겠습니다.

// function 키워드
function A(one) {
  this.one = one
}

A.prototype.getArguments = function() {
  return this.one
}

const a = new A(1)

// 클래스
class B {
  constructor(one) {
  	this.one = one
  }
  
  getArguments() {
    return this.one
  }
}

const b = new B(2)

일단 코드만 봐도 클래스를 쓰는 편이 더 보기도 좋고 의미도 들어나는 듯 합니다.
또, 이 외의 차이점도 있습니다.
function 키워드를 사용한 경우는 일반 함수의 역할도 가능하기 때문에 new 키워드 없이 호출해도 작동을 합니다. 그러나 클래스는 new 키워드 없이 사용하면 오류를 발생시킵니다.

A() // 작동함
B() // Uncaught TypeError: Class constructor B cannot be invoked without 'new'

그리고 arguments와 caller에 접근하는 경우 클래스 문법은 오류를 발생시키지만 function 키워드를 사용한 경우 그렇지 않습니다.

console.log(A.arguments) // null
console.log(A.caller)  // null

console.log(B.arguments) // Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
console.log(B.caller) // Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them

객체의 메서드

이번엔 객체의 메서드로 사용을 할 경우를 생각해 봅시다. 이 경우, function 키워드 대신 메서드 축약형을 사용할 수 있습니다.

const a = {
  name: "asdf",
  // function 키워드 사용
  call1: function() {
    console.log(this.name)
  },
  // 메서드 축약형
  call2() {
  	console.log(this.name)
  }
}

겉으로 보기엔 아무 문제가 없어 보입니다. 그러나 앞에서 봤듯이 function 키워드는 생성자 함수의 역할도 합니다. 그래서 이런 게 가능하죠.

console.log(new a.call1()) // 작동함

메서드 축약형의 경우 오류를 띄워줍니다.

console.log(new a.call2()) // Uncaught TypeError: a.call2 is not a constructor

예외

아직 설명하지 않은 것이 하나 있습니다. 바로 제네레이터 함수입니다.
제네레이터 함수의 경우 function이란 키워드가 꼭 들어가야 하기에 어쩔 수 없이 써야 합니다.

function* generator() {
  yield 1
  yield 2
}

대신 메서드로 제네레이터 함수를 쓰는 경우에는 메서드 축약형으로 쓸 수 있습니다.

const a = {
  *generator() {
  	yield 1
    yield 2
  }
}

왜 이럴까

이런건 js 문법이 이전 문법을 제거하거나 할 수 없는 특성때문에 그런 것 같습니다. 또, 화살표 함수, 메서드 축약형, 클래스가 추가된 es6 문법을 생각해봅시다. let, const의 의도가 var의 문제점을 해결하기 위했던 것 처럼, function 키워드의 문제점을 해결하기 위해 이런 문법을 새롭게 추가한 것 같습니다.
흠... 근데 왜 다들 'var 쓰지말고 let, const 쓰세요'라는 건 확실히 많이 퍼져있는 것 같은데 function 키워드에 대해선 왜 이런 말이 없는걸까요? 매우 궁금

결론

틀딱 문법인 function은 많은 역할을 가졌으며, 크리티컬한 문제도 에러를 띄워주지 않습니다. 물론 본인이 해당 키워드가 맘에 든다면 그냥 써도 무방하겠지만, 웬만하면 에러 잘 띄워주고 해당하는 목적에 더 알맞는 최신 문법을 애용합시다!

profile
아아

1개의 댓글

comment-user-thumbnail
2024년 5월 3일

역시 과거에 사용되었던 문법보다 현재 새롭게 나온 최신문법들이 과거의 문제점들을 해결해서 나오다 보니 최신문법을 사용하는게 좋은 거 같습니다.

답글 달기