개발여행의 블로그
[JavaScript] 반복문 for of / for in 사용법 그리고 차이 본문
✅ for ... of
The for...of statement creates a loop iterating over iterable objects, including: built-in String, Array, array-like objects (e.g., arguments or NodeList), TypedArray, Map, Set, and user-defined iterables. It invokes a custom iteration hook with statements to be executed for the value of each distinct property of the object.
for of 문은 iterable을 순회하면서 iterable의 요소를 변수에 할당한다.
내부적으로 iterator의 next 메서드를 호출하여 interable을 순회하며 next 메서드가 반환한 iterator result 객체의 value property 값을 for of문의 변수에 할당한다. 그리고 iterator result 객체의 done property 값이 false이면 iterable의 순회를 계속하고, true이면 순회를 중단한다.
for (변수 선언문 of iterable) { statement }
// 예시
const iterable = [10, 20, 30];
for (const value of iterable) {
console.log(value);
}
// 10
// 20
// 30
for of 문의 내부 동작을 for문으로 표현하면 아래와 같다.
const iterable = [1, 2, 3];
// iterable의 Symbol.iterator 메서드를 호출하여 iterator를 생성
const iterator = iterable[Symbol.iterator]();
for (;;) {
// iterator의 next 메서드를 호출하여 interable을 순회
// 이때, next 메서드는 iterator result 객체를 반환한다.
const result = iterator.next();
// next 메서드가 반환한 iterator result 객체의 done 프로퍼티 값이 true이면 iterable 순회 중단
if ( result.done ) break;
// iterator result 객체의 value 프로퍼티 값을 item 변수에 할당
const item = result.value;
console.log(item);
}
✅ for ... in
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.
객체의 모든 property를 순회하며 열거하려면 for in 문을 사용한다.
for in 문은 객체의 property 개수만큼 순회하며 for in 문의 변수 선언문에 선언한 변수에 property key를 할당한다.
- for in 문은 객체의 prototype chain 상에 존재하는 모든 prototype의 property 중에서 property attribute [[Enumerable]]의 값이 true인 property를 순회하며 열거한다. property key가 symbol인 property는 열거하지 않는다.
- for in 문은 in 연산자처럼 순회 대상 객체의 프로퍼티뿐만 아니라 상속받은 프로토타입의 프로퍼티까지 열거한다.
- 상속받은 프로퍼티는 제외하고 객체 자신의 프로퍼티만 열거하려면 Object.prototype.hasOwnProperty 메서드를 사용하여 객체 자신의 프로퍼티인지 확인해야 한다.
for (변수 선언문 in 객체) { statement }
// 예시
const object = { a: 1, b: 2, c: 3 };
for (const property in object) {
console.log(`${property}: ${object[property]}`);
}
// expected output:
// "a: 1"
// "b: 2"
// "c: 3"
※ 배열에는 for ... in 문을 사용하지 않고 일반적인 for 문이나 for ... of문 또는 Array.prototype.forEach 메서드를 사용하길 권장한다. (배열도 객체이므로 프로퍼티와 상속받은 프로퍼티가 포함될 수 있다.)
✅ for ... of 와 for ... in의 차이
for of와 for in은 둘 다 무언가를 반복한다. 하지만 주요 차이점은 '무엇을 반복하는지'이다.
for in 문은 객체의 열거 가능한 properties를 임의의 순서로 반복한다. for of 문은 iterable 객체가 반복하도록 정의한 값을 반복한다.
예시를 보자!
Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
const iterable = [3, 5, 7];
iterable.foo = 'hello';
for (const i in iterable) {
console.log(i); // "0", "1", "2", "foo", "arrCustom", "objCustom"
}
for (const i in iterable) {
if (iterable.hasOwnProperty(i)) {
console.log(i); // "0", "1", "2", "foo"
}
}
for (const i of iterable) {
console.log(i); // 3, 5, 7
}
위의 코드를 차근히 분석해보자!
Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
const iterable = [3, 5, 7];
iterable.foo = 'hello';
모든 객체는 objCustom 프로퍼티를 상속받고, Array인 모든 객체는 arrCustom 프로퍼티를 상속받는다.
iterable 객체는 상속과 프로토타입 체인의 영향으로 objCustom과 arrCustom 프로퍼티 둘 다 상속받는다.
for (const i in iterable) {
console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom"
}
위의 for in문은 임의의 순서로 iterable 객체의 열거 가능한 프로퍼티만 log로 출력한다.
Array 요소인 3, 5, 7이나 hello를 log로 출력하지 않는다.
위의 for in문은 Array의 index와 foo, arrCustom, objCustom을 출력한다.
> 3, 5, 7이나 hello는 사실상 프로퍼티가 아니라 값이기 때문에 열거 가능한 프로퍼티가 아니다.
for (const i in iterable) {
if (iterable.hasOwnProperty(i)) {
console.log(i); // 0, 1, 2, "foo"
}
}
위의 for in 문은 그 위의 for in문과 비슷하다. 하지만 hasOwnProperty 메서드로 열거 가능한 프로퍼티가 객체 자신의 프로퍼티인지 체크할 수 있다. 프로퍼티 0, 1, 2 및 foo는 고유 속성(상속 X)이므로 콘솔에 출력된다. 프로퍼티 rrCustom 및 objCustom은 상속되기 때문에 출력되지 않는다.
for (const i of iterable) {
console.log(i); // 3, 5, 7
}
마지막으로 for of 루프는 iterable 객체가 iterable이 반복하도록 정의한 값을 반복하고 콘솔에 출력한다.
for of 문에서는 Array의 요소인 3, 5, 7이 출력된 것을 볼 수 있다. (하지만 객체의 property는 출력되지 않는다.)
이 글은 '모던 자바스크립트 Deep Dive'와 MDN의 for ... in, for ... of를 참고하여 작성한 글입니다.
'개발 > javaScript' 카테고리의 다른 글
[JavaScript] 왜 Object(객체)는 Iterable object가 아닌것일까? (iterable과 iterator에 대해 알아보자!) (0) | 2021.11.26 |
---|---|
[JavaScript] 단축 평가 (논리 연산자 ||, && / null 병합 연산자 ?? /옵셔널 체이닝 ?) (0) | 2021.09.05 |
[JavaScript] 실행 컨텍스트 Execution Context (1) (0) | 2021.09.01 |
[JavaScript] 생성자 함수 (0) | 2021.08.27 |
[JavaScript] Method Chaining (메서드 체이닝) (0) | 2021.08.26 |