다양한 곳에서 사용되어 오히려 헷갈리는 기존 function 키워드

예시 1) 일반 함수로 활용

출력 결과는 다음과 같습니다.

여기서 this 는 window 를 가리킵니다.

예시 2) 생성자 함수로 활용

출력 결과는 다음과 같습니다.

여기서 가리키는 this 는 Func 클래스에 의해 만들어진 인스턴스입니다.

this 가 windows 가 아니기 때문에 func 라고 하는 인스턴스에 프로퍼티 args 를 만들어서 거기에 배열을 담고 있게 됩니다.

예시 3) 객체 메소드로 활용

출력 결과는 다음과 같습니다.

객체에 있는 메소드를 실행했을 때 this 는 . 앞에 있는 bar 가 됩니다.

위와 같이 function 키워드는 일반 함수로도 객체 생성자 함수로도 객체 메서드로 활용될 수 있다 보니 범용적으로 쓸 수 있다는 측면에서는 좋습니다. 

하지만 오히려 이게 문제를 일으킬 수도 있습니다.

 

function 키워드를 사용하여 a 함수를 선언 후 콘솔로 값을 출력해보았는데요.

a 함수는 arguments 를 비롯해서 다양한 프로퍼티를 가지고 있음을 알 수 있습니다.

이 프로퍼티들이 위의 예시에서 모두 사용되는 것은 아닙니다.

일반 함수로 활용되는 경우, prototype 프로퍼티는 불필요합니다. prototype 프로퍼티는 생성자 함수로 활용되는 경우에만 필요합니다.

객체 메서드로 활용되는 경우, this 바인딩에 의해 this 가 해당 객체를 가리키게 됩니다.

참고) this 는 실행 컨텍스트 생성 시점에 할당됩니다.

이는 this 를 쓸 경우에는 좋지만 함수로 쓸 때는 불필요한 정보입니다.

this 는 동적으로 바인딩되기 때문에 이는 오히려 혼란을 가중시킬 수 있습니다. 

 

그래서 ES2015에서는 일반 함수로 활용, 생성자 함수로 활용, 객체 메서드로 활용할 때 그 목적에 맞는 정확한 기능들이 추가되었습니다.

function 키워드를 대체할 ES 2015 문법 살펴보기

1. class 의 등장

function 키워드로 선언한 생성자 함수

출력 결과 :

function 키워드로 선언한 생성자 함수에 할당된 getArgs 함수는 enumerable 값이 true 로 설정됩니다.

이에 따라 for ... in 문을 통해 생성자 함수의 프로퍼티를 순회할 때 getArgs 함수가 반복 출력됩니다.

 

생성자 함수의 프로퍼티 순회 시 프로토타입에 있는 프로퍼티를 제외시키고 싶다면(여기서는 getArgs 함수), 다음과 같이 따로 조건문을 설정해줘야 합니다. 

반면, class 키워드로 선언언한 클래스에 선언한 getArgs 메서드는 enumerable 값이 false 로 설정됩니다.

for ... in 문을 통해 클래스의 프로퍼티를 순회할 때 getArgs 함수가 반복 출력되지 않습니다. 

 클래스는 hasOwnProperty 메소드를 따로 사용하지 않아도 객체 인스턴스 자신에게 있는 값만 순회를 돌 수 있어 개발자가 신경써야 할 부분이 줄어들었습니다.

 

function 키워드로 선언한 Func 생성자 함수와 class 키워드로 선언한 Bar 클래스 자체 비교

- Func 의 경우 arguments 값을 출력하지만, Bar 의 경우 위와 같은 에러를 던집니다.

- Func 의 경우 함수, 객체 생성자로 사용할 수 있어 new 키워드 없이도 호출될 수 있지만 Bar 의 경우 new 키워드 없이 호출될 수 없습니다.

 

결론 : 객체 생성자 함수를 선언할 때는 class 키워드를 사용하라.

2. arrow function

내가 가지고 있었던 오해) arrow function 을 간략한 함수일 경우에만 사용하고 나머지 경우에는 function 키워드를 사용한다.

function 키워드로 선언한 함수와 arrow function 으로 선언한 함수 비교

출력 결과는 다음과 같습니다.

arrow function 은,

- prototype 이 없어 생성자로 사용할 수 없습니다.

- arguments 프로퍼티 값 접근 시 반드시 getter 를 호출해야 합니다.

- this 바인딩을 하지 않습니다.

- call, apply 메서드로도 this 바인딩을 할 수 없습니다.

 

애초부터 함수로 사용한다고 하면 this를 신경 쓸 이유가 없습니다.

this 를 써야 된다면 객체 메서드 선언 방식을 쓰면 됩니다.

결론 :  this 를 신경쓰지 않고 일반 함수로만 사용한다면 arrow function 을 사용하자.

 3. 메서드 축약형

function 키워드로 선언한 객체 메서드와 메서드 축약형으로 선언한 객체 메서드 비교

출력 결과는 다음과 같다.

메서드 축약형으로 선언한 객체 메서드는,

- prototype 이 없어 생성자 함수로 쓸 수 없습니다.

- arguments 프로퍼티 값 접근 시 반드시 getter 를 호출해야 합니다.

- arrow 함수와 다르게 this 바인딩이 됩니다.

 

각 객체 별로 선언한 메서드를 호출한 결과는 다음과 같습니다.

각 객체 별 name 프로퍼티 값이 정상적으로 출력됨을 알 수 있습니다. 

예외적으로 반드시 function 키워드를 사용해야 하는 경우) generator

함수 형태의 generator 에서만 이 function 키워드가 필요합니다.

객체 안에서 generator 를 만들 경우는 다음과 같습니다. (메서드 축약형 사용)

 

이 생김새 그 자체만으로도 다른 가능성이 있다는 걸 열어두지 않고 한 가지 기능만 할 것이라고 생각하는 것이 다른 사람이 내 코드를 봤을 때 좀 더 빨리 이해할 수 있는 지름길이라고 생각합니다.

정리

기존 함수는 다양한 목적에 두루 쓸 수 있는 만능 키워드입니다.

무겁고, 상황에 따라 개발자가 추가로 번거로운 작업을 해줘야 하거나 안전장치를 마련해야 하는 등의 문제가 있습니다.

그러므로,

함수로 쓰고자 할 때는 arrow function 사용

생성자 함수로 쓰고자 할 때는 class 사용

메서드로 쓰고자 할 때는 method 축약형 사용

을 권장합니다.

function 키워드는 generator 를 선언하는 경우를 제외하고는 거의 쓰이지 않습니다.

 

참조

[JavaScript 미세팁] function은 아예 쓰지 마세요 : https://www.youtube.com/watch?v=LPEwb5plEoU 

복사했습니다!