for-in 루프에서 열거 가능한 속성과 그렇지 않은 속성의 차이
조회수 774회
Object.prototype.contain = function(neddle) {
for(var name in this){
if(this[name] === neddle){
return true;
}
}
return false;
}
var o = {'name':'egoing', 'city':'seoul'};
for(var key in o){
console.log(key);
}
console에서
name
city
contain
이렇게 출력됩니다.
Object.prototype.contain = function~~
으로 지정한 속성이 왜 생성한 객체를 출력시킬 때 출력되나요? 이미 Object.prototype
에서 기본적으로 정의된 다른 속성들도 많은데 왜 직전에 정의한 contain
만 하나 더 출력되는건지 궁금합니다.
1 답변
-
기본적으로 사용자가 어떤 객체의 프로토타입을 확장하여 만든 속성값들은 그 확장된 객체가 인스턴스화 될 때 인스턴스의 enumerable entry에 포함됩니다. 이것은 JS의 프로토타입을 통한 상속 특성에 기인하는데 자세한 것은 프로토 타입 체인 설명을 살펴보세요.
그렇다면 왜
Object.prototype
안에 있는 다른 속성들은for..in
에서 나타나지 않을까요?이것은 해당 속성의 명세(property description)에 나타나 있습니다. 속성 명세를 얻기 위해서 Object.getOwnPropertyDescriptor()를 사용하는데요.
Object를 상속받은 모든 객체가 가지고 있지만
for..in
에 노출되지 않는 대표적인 속성인toString
을 살펴보면,var desc = Object.getOwnPropertyDescriptor(Object.prototype, 'toString'); console.log(desc); /* { value: [Function: toString], writable: true, enumerable: false, configurable: true } */
이런 결과가 나옵니다.
여기에서 눈여겨 보아야 할 것은
enumerable: false
입니다.The for...in statement iterates over all enumerable properties of an object that are keyed by strings (ignoring ones keyed by Symbols), including inherited enumerable properties.
enumerable properties
라는 말이 나옵니다. 이것은열거 가능한 속성
이라는 의미인데, 이 열거와 관련된 제어 속성이 위에 봤던enumerable
입니다.Object.toString
속성은enumerable: false
이므로 열거 가능하지 않게 지정되어 있다고 보면 되며, 결국for..in
반복문을 돌 때 skip되어 넘어가는 것입니다.이를 좀 더 쉽게 이해하기 위해 질문 코드를 바꿔볼게요. 프로토타입 확장된
contain
속성을 열거가 불가능하게 지정하여for..in
에서 노출시키지 않도록 하는 코드입니다. 속성 명세를 정의하기 위해서는 Object.defineProperty()를 사용합니다.Object.prototype.contain = function(neddle) { for(var name in this){ if(this[name] === neddle){ return true; } } return false; } // 여기서 'contain' property의 특성을 지정합니다. Object.defineProperty(Object.prototype, 'contain', { enumerable: false // 열거 불가능한 속성으로 지정 }); var o = {'name':'egoing', 'city':'seoul'}; for(var key in o){ console.log(key); } /* name city */
위 결과에서 추가로 알 수 있는 두 가지 사실은,
- 사용자가 확장하는 속성은
enumerable
명세가 기본으로(by default)true
이다. - 표준 내장 객체의 기본 속성 혹은 prototype 속성들은 대부분
enumerable: false
로 지정되어 있다.
eg.
Object.getOwnPropertyDescriptor(Math, 'pow') // {writable: true, enumerable: false, configurable: true, value: ƒ}
이 내용들은 직접 테스트 코드를 작성하여 확인해 보시면 될 것 같고요.
이 현상과 관련하여
hasOwnProperty
함수의 동작 원리와Symbol
속성에 대해for..in
이 어떻게 동작하는지를 추가로 알아두시면 대부분 이해했다고 볼 수 있겠네요. - 사용자가 확장하는 속성은
댓글 입력