for...in 과 for...of의 차이에 대해 알아보겠습니다.
for...in
- for...in 문은 상속된 열거 가능한 속성들을 포함하여 객체에서 문자열로 키가 지정된 모든 열거 가능한 속성에 대해 반복합니다.
for (variable in object) {
statement;
}
열거 가능한 속성(enumerable)
- 객체를 선언하여 살펴보면 [[Prototype]] 이라는 것이 있습니다.
- 열거 가능한 속성이 무엇인지 이해하기 위해 Prototype에 대해 먼저 정리해보겠습니다.
Prototype
- JS는 프로토타입 기반 객체지향언어이며, 프로토타입 체인을 통해 속성을 상속합니다.
- JS의 모든 객체는 부모 역할의 객체와 연결되어 있어, 부모 객체의 프로퍼티 또는 메소드를 상속받아 사용할 수 있습니다.
- 이러한 부모 객체를 프로토타입(Prototype)이라 합니다.
- 직접 생성한 속성은 기본적으로 열거 가능하며, 프로토타입 체인을 통해 상속받은 속성은 속성 명세의
enumerable
값에 따라 달라집니다.
enumerable
Object.getOwnPropertyDescriptor()
함수를 사용하여 enumerable 값을 확인할 수 있습니다.enumerable: false
라면 열거 가능하지 않은 속성이며,enumerable: true
라면 열거 가능한 속성입니다.- 아래와 같이 toString 메서드는 열거 가능하지 않은 속성이기에 for...in 루프로 객체 속성을 반복하더라도 toString은 나오지 않는 것입니다.
const desc = Object.getOwnPropertyDescriptor(Object.prototype, "toString");
console.log(desc);
/*
{ value: [Function: toString],
writable: true,
enumerable: false,
configurable: true }
*/
- 프로토타입으로부터 열거 가능하지 않은 속성을 상속받았으나 프로토타입 체인 상에 있는 속성과 객체 자체에 있는 속성이 충돌한다면, 객체 자체의 프로퍼티를 우선합니다.
- 아래와 같이 객체 안에서 toString을 새롭게 작성했을 경우, 이는 프로토타입 체인 상의 toString과 충돌하기에 커스텀한 toString이 우선시 되어 for...in 루프에서 반복할 수 있는 것입니다.
const obj = {
a: 1,
b: 2,
toString: function () {
console.log("Custom toString");
},
};
for (const key in obj) {
console.log(obj[key]);
/*
1
2
ƒ () {
console.log('Custom toString');
}
*/
}
for...of
- for...of 문은 반복가능한 객체(Array, Map, Set, String, TypedArray, Arguments 객체 등)에 대해서 반복합니다.
- [Symbol.iterator] 속성이 있는 모든 컬렉션 요소에 대해 반복합니다.
for (variable of iterable) {
statement;
}
[Symbol.iterator] 속성
- 배열을 선언하여 살펴보면 Symbol.iterator 속성이 있습니다.
- [Symbol.iterator] 속성을 이해하려면 이터레이션 프로토콜을 먼저 이해해야 합니다.
이터레이션 프로토콜(iteration protocol)
- ES6에서 도입된 이터레이션 프로토콜(iteration protocol)은 데이터 컬렉션을 순회하기 위한 프로토콜(미리 약속된 규칙)입니다.
- 이터레이션 프로토콜을 준수한 객체는
for…of
문으로 순회할 수 있고 Spread 문법(...)의 피연산자가 될 수 있습니다. - 이터레이션 프로토콜에는 이터러블 프로토콜(iterable protocol)과 이터레이터 프로토콜(iterator protocol)이 있습니다.
- 이중에서 이터러블 프로토콜을 준수한 객체를 이터러블(iterable)이라 합니다.
- 이터러블 프로토콜을 따르는 객체는 반드시 Symbol.iterator 메서드를 구현하거나 프로토타입 체인에 의해 상속해야 합니다.
그럼 다시 [Symbol.iterator] 이야기로 돌아가보겠습니다.
- ES6에서 제공하는 빌트인 이터러블에는 Array, String, Map, Set, TypedArray(Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array), DOM data structure(NodeList, HTMLCollection), Arguments가 있습니다.
- 이러한 요소들의 속성을 살펴보면 Symbol.iterator가 있습니다. 즉, for...of로 순회할 수 있다는 뜻입니다.
결론
- 객체의 속성을 반복할 때는
for...in
을 사용합니다. - 배열, 문자열, Map, Set 등을 반복할 때는
for...of
를 사용합니다.
참고
- MDN
- 블로그
- PoiemaWeb
- 프로그래머스 Q&A
'Language > JavaScript' 카테고리의 다른 글
parseInt( ) vs Number( ) (0) | 2024.08.27 |
---|---|
[JS] JavaScript의 일급객체란? (0) | 2024.07.05 |