객체 프로퍼티나열 다시 보기
for…in 문으로 객체의 프로퍼티를 나열하는 방법은 이미 봤습니다. 이제 프로토타입 상속에 대해 알게 됐으니 객체의 프로퍼티를 나열할 때 hasOwnProperty가 어떤 의미가 있는지 완전히 이해할 수 있습니다. 객체 obj와 프로퍼티 x에서, obj,hasOwnProperty(x)는 obj에 프로퍼티 x가 있다면 true를 반환하며, 프로퍼티 x가 obj에 정의되지 않았거나 프로토타입 체인에만 정의되었다면 false를 반환합니다.
ES6 클래스를 설계 의도대로 사용한다면 데이터 프로퍼티는 항상 프로토타입 체인이 아니라 인스턴스에 정의해야 합니다. 하지만 프로퍼티를 프로토타입에 정의하지 못하도록 강제하는 장치는 없으므로, 확실히 하려면 항상 hasOwnProperty를 사용하는 편이 좋습니다. 예제를 볼까요.
class Super {
constructor() {
this.name = 'Super';
this.isSuper = true;
}
}
//유효하나 권장하지는 않음
Super.prototype.sneaky = 'not recommended!';
class Sub extends Super {
constructor() {
super();
this.name = 'Sub';
this.isSub = true;
}
}
const obj = new Sub();
for(let p in obj) {
console.log(`${p} : ${obj[p]}` (obj.hasOwnProperty(p) ? '' : ' (상속!)'));
}
이 프로그램을 실행한 결과는 다음과 같습니다.
name : Sub
isSuper : true
isSub : true
sneaky : not recommended! (상속!)
name, isSuper, isSub 프로퍼티는 모두 프로토타입 체인이 아니라 인스턴스에 정의됐습니다(슈퍼클래스 생성자에서 선언한 프로퍼티는 서브클래스 인스턴스에도 정의됩니다). 반면 sneaky 프로퍼티는 슈퍼클래스의 프로토타입에 직접 정의했습니다(프로토타입에 정의된 프로퍼티로, obj의 프로퍼티가 아닌 상속된 프로퍼티입니다).
Object.keys를 사용하면 프로토타입 체인에 정의된 프로퍼티를 나열하는 문제를 피할 수 있습니다.