해당 포스팅은 위키북스의 모던 자바스크립트 Deep Dive라는 책을 독학하며 기록하는 글입니다.

ES6 이전의 모든 함수는 일반 함수로서 호출할 수 있는 것은 물론 생성자 함수로서 호출할 수 있다. 즉 ES6 이전의 모든 함수는 callable이면서 constructor이다.

이게 문제가 될 수 있는 것은 객체에 바인딩된 함수가 constructor라는 것은 객체에 바인딩된 함수가 prototype 프로퍼티를 가지며, 프로토타입 객체도 생성한다는 것을 의미하는데 이믐 불필요한 프로토타입 객체를 생성하는 것이기 때문이다. 함수에 전달되는 콜백 함수도 마찬가지인데 이처럼 ES6 이전의 모든 함수는 사용 목적에따라 명확한 구분이 없으므로 호출 방식에 특별한 제약이 없고 생성자 함수로 호출되지 않아도 프로토타입 객체를 생성한다.

이러한 문제를 해결하기 위해 ES6에서는 함수를 사용 목적에 따라 세 가지 종류로 명확히 구분했다.

  1. 일반함수

  2. 메서드

  3. 화살표 함수

메서드

ES6 사양에서의 메서드는 메서드 툭양 표현으로 정의된 함수만을 의미하는데 이러한 메서드는 ES6 이전의 메서드와는 다르게 non-constructor이다. 따라서 prototype 프로퍼티도 없고 프로토타입 객체도 생성하지 않는다.

ES6 사양에서의 메서드는 자신을 바인딩한 객체를 가리키는 내부 슬롯인 [[HomeObject]]를 갖는다. 따라서 [[HomeObject]]를 사용하는 super를 사용할 수 있으며 ES6에서 메서드가 아닌 함수들은 super 키워드를 사용할 수 없다. ([[HomeObject]]가 없기 때문에)

화살표 함수

function 키워드 대신 화살표를 사용하여 기존의 함수 정의 방식보다 간략하게 함수를 정의한 것으로 표현만 간략한 것이 아니라 내부 동작도 기존의 함수보다 간략하다.

  • 정의 : 화살표 함수의 정의는 다음과 같다.
const sum = (x, y) => x + y;
sum(2, 3);  // 5
  • 매개변수 : 매개변수가 여러 개인 경우 소괄호 안에 매개변수를 선언하고, 한 개인 경우 소괄호를 생략할 수 있다. 하지만 매개변수가 없는 경우 소괄호를 생략할 순 없다.

  • 함수몸체 : 함수의 몸체가 하나의 문으로 구성된다면 중괄호를 생략할 수 있는데 이때 하나의 문이 값으로 평가될 수 있는 표현식인 문이여야 한다.(아닌 경우 에러 발생) 만약 여러 개의 문으로 구성된다면 중괄호를 생략할 수 없다.

  • 객체반환 : 만약 객체 리터럴을 반환하는 경우에는 객체리터럴을 소괄호로 감싸 주어야 한다. 왜냐하면 소괄호가 없을 시 객체 리터럴을 감싸는 중괄호를 함수 몸체를 정의하는 중괄호로 잘못 인식할 수 있기 때문이다.

화살표 함수 또한 즉시 실행 함수로 사용할 수 있으며 일급 객체이므로 고차 함수에 인수로 전달할 수 있다.(콜백함수)

또한 일반 함수와는 구분되는 몇 가지 차이점이 있는 다음과 같다.

  1. 화살표 함수는 non-constructor이다.
  2. 중복된 매개변수 이름을 선언할 수 없다. (일반함수에서는 strict mode가 아니라면 중복된 매개변수 이름 사용 가능)
  3. 화살표 함수는 함수 자체의 this, arguments, super, new.target 바인딩을 갖지 않는다.
  4. this의 바인딩

화살표 함수가 일반 함수와 구별되는 가장 큰 특징은 바로 this인데, this는 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정되는 특징이 있다. 화살표 함수로 함수가 호출되는 경우 화살표 함수 내부에 있는 this에는 함수의 상위 스코프의 this가 그대로 바인딩된다. 이는 콜백 함수 내부의 this 문제를 해결하기에 좋다.

화살표 함수에서의 super 또한 this와 마찬가지로 함수 자체의 바인딩을 가지고 있지 않으므로 상위 스코프의 super를 참조한다.

Rest 파라미터

Rest 파라이터란 매개변수 이름 앞에 세 개의 점(...)을 분혀 정의 매개변수를 의미하는데 해당 매개변수에는 함수에 전달된 인수들의 목록들이 모두 배열의 형태로 담겨 전달된다. 예를 들면 다음과 같다.

function rest(...a) {
  console.log(a);
}

rest(1, 2, 3, 4, 5);  //  [1, 2, 3, 4, 5]

일반 매개변수와 Rest 매개변수를 섞어 사용할 수 있지만 몇 가지 규칙이 있다.

  1. 일반 매개변수를 항상 앞에 사용하고 매개변수들 중 맨 마지막에 Rest 매개변수를 사용해야 한다. 왜냐하면 인자로 들어온 것들을 앞에서부터 차례로 하나씩 할당하고 남은 모든 인자들은 Rest 매개변수에 할달하기 때문이다.
  2. Rest 매개변수는 단 하나만 선언할 수 있다.
  3. Rest 매개변수는 함수 객체가 전달받고자 하는 인자의 개수를 나타내는 프로퍼티인 length에 영향을 주지 않는다.
function len(a, ...b) { }
console.log(len.length);  //  1

Rest 매개변수와 비슷하게 함수 내부에서 함수가 전달받은 모든 인자들을 저장하는 arguments 객체가 있는데 이 둘의 차이점은 arguments 객체의 경우 유사배열이라 Array 객체에서 제공하는 prototype 메서드들을 call과 apply 등의 간접호출을 통해 사용해야 하지만 Rest 매개변수의 경우 유사배열이 아닌 배열로 들어와 직접 Array 객체의 prototype 메서드들을 호출할 수 있다.

함수의 매개변수는 있지만 인자가 전달되지 않는 경우 여타 다른 프로그래밍 언어의 경우 오류가 나지만 자바스크립트의 경우는 자바스크립트 엔진이 매개변수의 개수와 인수의 개수를 체크하지 않기 때문에 오류가 발생되지 않고 전달되지 않은 매개변수에 대해 undefined가 할당된다.

이는 나중에 큰 문제를 일으킬 수 있기 때문에 항상 기본값을 할당하는 방어 코드를 작성하는 습관을 들이도록 하는 것이 좋다. 다음의 예제를 보자.

function sum(a = 0, b = 0) {
  return a + b;
}

console.log(sum(2, 3));  //  5
console.log(sum(2));  //  2
console.log(sum());  //  0

위와 같이 매개변수 a, b에 기본값으로 0을 할당하는 방어 코드를 작성하므로써 NaN과 같은 이상한 값이 출력되는 것을 방지할 수 있다. 기본값을 매개변수가 전달되지 않거나 undefined가 전달되었을 때 적용된다.

또한 Rest 매개변수에는 기본값을 할당할 수 없으며, Rest 매개변수와 마찬가지로 함수 객체의 lenght 프로퍼타와 arguments 객체에 영향을 주지 않는다.

profile
I Will be Relaxed Person

0개의 댓글