내장 객체와 정적 메서드 상속
내장 객체는 Object.keys
, Array.isArray
등의 자체 메서드를 갖는다.
그리고, Array
가 Object
를 상속받듯이 네이티브 클래스들은 서로 상속 관계를 맺는다. 이렇게 한 클래스가 다른 클래스를 상속받으면 보통의 경우에는 정적 메서드와 그 외 메서드 모두를 상속받게 된다.
그런데 내장 클래스는 정적 메서드를 상속받지 못한다.
위의 이미지와 같이 Array
와 Date
는 모두 Object
를 상속받기 때문에 두 클래스의 인스턴스에선 Object.prototype
에 구현된 메서드를 사용 가능하다. 그런데 Array.prototype
과 Date.prototype
은 Object
가 아니라 Object.prototype을 참조하기 때문에 Array.keys()
나 Date.keys()
와 같은 정적 메서드를 인스턴스에서 사용할 수 없다.
내장 객체 간의 상속과 extends
를 사용한 상속의 가장 큰 차이점이 여기에 있다.
내장 클래스 확장하기
extends
를 사용하면 내장 클래스 간의 상속과 달리 정적 메서드까지 모두 상속 받는 것이 가능하다.
// 메서드 하나를 추가합니다(더 많이 추가하는 것도 가능).
class PowerArray extends Array {
isEmpty() {
return this.length === 0;
}
}
let arr = new PowerArray(1, 2, 5, 10, 50);
alert(arr.isEmpty()); // false
let filteredArr = arr.filter(item => item >= 10);
alert(filteredArr); // 10, 50
alert(filteredArr.isEmpty()); // false
여기서 주목할 점은 filter
, map
등의 내장 메서드가 상속받은 클래스인 PowerArray
의 인스턴스를 반환한다는 것이다.
따라서 arr.constructor === PowerArray
임을 확인할 수 있다.
그래서 arr.filter()
가 호출될 때는 기본 Array가 아니라 arr.constructor
를 기반으로 새로운 배열이 만들어지는데, 이 때 PowerArray
에 구현되어 있는 메서드도 사용 가능하다.
만약 내장 메서드가 일반 배열을 반환하도록 하고 싶을 때는 특수 정적 getter인 Symbol.species
를 추가하면 된다.
class PowerArray extends Array {
isEmpty() {
return this.length === 0;
}
// 내장 메서드는 반환 값에 명시된 클래스를 생성자로 사용합니다.
static get [Symbol.species]() {
return Array;
}
}
let arr = new PowerArray(1, 2, 5, 10, 50);
alert(arr.isEmpty()); // false
// filter는 arr.constructor[Symbol.species]를 생성자로 사용해 새로운 배열을 만듭니다.
let filteredArr = arr.filter(item => item >= 10);
// filteredArr는 PowerArray가 아닌 Array의 인스턴스입니다.
alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function
댓글