[ ES6 ] 클래스 내에서 arrow 함수와 메서드의 차이점

작성배경

리액트를 사용할 때, 메서드안에서 this 를 참조하고 하위 컴포넌트에 props로 내려주기 전에 binding을 하는 경우가 빈번하다. 내 다른 포스팅에서도 보았듯이 렉시컬-스코프인 arrow function 으로 작성 후 멤버변수에 할당함으로써 바인딩 문제를 해결 하는경우가 대부분일 것이다. 이때 내부적으로 정의가 달라지게 되는 것을 알게되었는데 그것을 한번 살펴보자.

BABEL 으로 트랜스파일 한 것을 살펴보자!

아래의 사진에서 음영처리된 class-fields 부분을 살펴보자 한개는 멤버변수에 arrow 함수 할당, 나머지 한개는 일반적인 method이다.

트랜스파일된 모습 by Babel

결과를 정리하자면 이렇다.

  1. arrow 함수 : App.ArrowFunc 로 정의 된다.
  2. 클래스 method: App.prototype.Func 로 정의된다.

console.log(App.prototype) 을 실행 시킨다면 결과 값은 다음과 같다.

“{ constructor: ƒ, Func: ƒ}”

클래스 메서드는 공유 메소드로 상속받은 컴포넌트에서 참조할 수 있지만, arrow 함수는 그렇지 못하다.

그렇다면?

클래스 메서드는 프로토타입에 정의되어 있으며 모든 인스턴스에서 공유된다. N 개의 상속받은 클래스가 있는 경우, 각각 동일한 메소드를 공유한다. 따라서 해당 메서드를 사용하면, 우리는 여전히 N 번 메소드를 호출하지만 동일한 프로토타입을 호출하는 것이다. 프로토타입 전역에서 동일한 메소드를 여러 번 호출하면 JavaScript 엔진이 이를 최적화 할 수 있다고 한다.

반면에 클래스 멤버변수에 할당된 화살표 함수에 대해 N 개의 클래스를 만들면이 N 개의 클래스들과 상응하여 N 개의 함수를 만들게된다. 위의 트랜스파일 된 이미지에서 본 것을 살펴보면 공유 될 수 없다는 것을 알 수 있다.

벤치마크

테스트 환경 : MacBook Pro 13" 2016 2GHz on Mac OS X 10.13.1 and Chrome 62.0.3202.

100개의 컴포넌트에서 메소드를 호출했을 때 벤치마크 (높을수록 좋다)

마치며

render 함수 내 에서 arrow-function 을 사용하고 props 로 내려 준다면, 자식 컴포넌트를 호출 할 때 마다 새로운 함수 객체 인스턴스를 생성하고 이는 동치비교를 할 수 없게 만들어 성능 저하를 유발 할 수 있다는 것이다. 그러므로 간편한 바인딩을 위해, 에로우 펑션 멤버변수 할당을 하는것은 컴포넌트 composition 을 추구하는 리액트 안에서는 일반적인 경우에는 문제가 되지않는다. 하지만 해당 클래스를 상속받아 다른 곳에서 사용할 경우에는 문제가 될 수 있다.

참조 : Arrow Functions in Class Properties Might Not Be As Great As We Think

--

--

Woowabros software engineer

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store