[딥다이브] 26. ES6 함수의 추가 기능
26.1 함수의 구분
모든 함수는 callable(메서드, 일반 함수)이면서 constructor(생성자 함수)
모든 함수가 constructor이기 때문에 불필요하게 prototype 프로퍼티를 가지고, 프로토타입 객체를 생성함
-> 의도치 않은 동작이 발생할 수 있으며, 성능에도 좋지 않음
ES6부터 사용 목적에 따라 함수를 세 종류로 명확히 구분
constructor | prototype | super | arguments | |
일반 함수 | O | O | X | O |
메서드 | X | X | O | O |
화살표 함수 | X | X | X | X |
26.2. 메서드
이전: 객체에 바인딩된 함수
ES6 이후: 메서드 축약 표현으로 정의된 함수
프로퍼티 값으로 익명 함수 표현식을 할당하는 방식 지양
// 지양
const obj = {
fn: function () {},
};
non-constructor, prototype 프로퍼티가 없고, 프로토타입을 생성하지도 않음
표준 빌트인 객체가 제공하는 프로토타입/정적 메서드는 모두 non-constructor
ES6 메서드는 자신을 바인딩한 객체를 가리키는 내부 슬롯 [[HomeObject]]를 가짐
[[HomeObject]]를 사용하여 수퍼클래스의 메서드를 참조 => [[HomeObject]]를 가진다면 super 키워드를 사용할 수 있음
(ES6 메서드가 아닌 함수는 [[HomeObject]]를 갖지 않기 때문에 super를 사용할 수 없음)
26.3 화살표 함수
콜백 함수의 this가 전역 객체를 가리키는 문제를 해결하기 위한 대안임
- 함수 표현식으로 정의
- 매개변수가 하나인 경우 소괄호 생략 가능, 없거나 여럿인 경우 생략 불가
- 함수 몸체가 하나의 문으로 구성된다면 중괄호 생략 가능
- 표현식인 문이라면 암묵적으로 반환
- 표현식이 아닌 문이라면 반환할 수 없기 때문에 에러 발생 - 객체 리터럴을 반환하는 경우 소괄호로 감싸주어야 함(감싸지 않는다면 함수 몸체를 감싸는 중괄호로 잘못 해석함)
- 콜백 함수로 전달 시 간결하여 가독성이 좋음
- non-constructor
- 중복된 매개변수 이름을 선언하면 에러 발생(일반 함수는 에러가 발생하지 않고 strict mode에서만 에러 발생)
- this, arguments, super, new.target 바인딩을 갖지 않아 해당 키워드 참조 시 스코프 체인을 통해 상위 스코프의 키워드를 참조
3. this
콜백 함수 내부의 this가 외부 함수의 this와 다르기 때문에 발생하는 문제를 해결하기 위해 의도적으로 설계됨
lexical this
: 화살표 함수는 this 바인딩을 갖지 않기 때문에 화살표 함수 내부에서 this를 참조하면 상위 스코프의 this를 참조,
화살표 함수의 this가 함수가 정의된 위치에 의해 결정되는 것을 의미함
스코프 체인 상 가장 가까운 상위 함수 중 화살표 함수가 아닌 함수의 this 참조(전역 함수인 경우 전역 객체를 가리킴)
class Prefixer {
constuctor(prefix) {
this.prefix = prefix;
}
add(arr) {
return arr.map((item) => this.prefix + item)
}
}
이전
- 참조를 변수로 받아 this를 우회적으로 사용
add(arr) {
const that = this;
return arr.map(function(item) {
return that.prefix + item;
})
}
- ES5부터 map의 두번째 인자로 this로 사용할 객체 전달
add(arr) {
return arr.map(function(item) {
return this.prefix + item;
}, this)
}
- bind 메서드 사용
add(arr) {
return arr.map(function(item) {
return this.prefix + item;
}.bind(this))
}
화살표 함수는 this 바인딩을 갖지 않기 때문에 Function.prototype.call/apply/bind 메서드를 사용하여 this를 교체할 수 없음
- 항상 상위 스코프의 this를 참조
메서드 정의 시 화살표 함수로 정의하는 경우 this 참조 불가
- 정의되어 있는 객체가 아닌 상위 스코프의 this를 참조하기 때문
-> 메서드 축약 표현으로 정의할 것
프로토타입 객체의 프로퍼티에 화살표 함수를 할당하는 경우도 this 참조 불가
-> 메서드 축약 표현 사용
- 클래스 필드 정의 제안을 사용하여 클래스 필드에 화살표 함수 할당 가능(인스턴스 메서드라 성능에 좋지 않음 )
class Person {
name = 'Lee';
sayHi = () => console.log(`Hi ${this.name}`)
}
- 프로토타입 객체에 프로퍼티를 동적으로 추가할 경우 메서드 축약 표현을 사용할 수 없으므로 일반 함수 할당, 혹은 프로토타입의 constructor 프로퍼티와 생성자 함수 간 연결 재설정
Person.prototype.sayHi = function () { console.log(`Hi ${this.name}`); };
Person.prototype = {
constructor: Person,
sayHi() { console.log(`Hi ${this.name}`); }
}
4. super
화살표 함수는 super 바인딩을 갖지 않기 때문에 상위 스코프의 super 참조
super는 [[HomeObject]]를 가지고 있는 ES6 메서드 내에서만 사용할 수 있지만
화살표 함수의 super는 상위 스코프의 super를 참조하기 때문에 에러가 발생하지 않음
5. arguments
화살표 함수는 arguments 바인딩을 갖지 않아 상위 스코프의 arguments 참조
화살표 함수로 가변 인자 함수를 구현해야하는 경우 Rest 파라미터 사용
26.4 Rest 파라미터
함수에 전달된 인수들의 목록을 배열로 전달받음
일반 매개변수와 함께 사용 가능
반드시 마지막 파라미터여야 함 tempFn(a, b, ...rest)
함수 객체의 length 프로퍼티(선언한 매개변수 개수를 나타냄)에 반영되지 않고 제외됨
arguments 객체: 전달된 인수들의 정보를 담고 있는 유사 배열 객체(배열처럼 다루고 싶은 경우 call/apply 메서드 사용해야 함)
26.5 매개변수 기본값
인수를 전달하지 않은 경우, undefined를 전달한 경우 유효함
Rest 파라미터에는 기본값을 지정할 수 없음
함수 객체의 length와 arguments에 영향을 주지 않음(반영되지 않음)