2019. 06. 09 수정


1. Iteration이란?

Iteration이란 사전적 의미로 "되풀이"를 의미하며, while문, for문과 같은 문법을 Iteration이라 합니다.


일반적으로 아래와 같이 Array를 반복문으로 돌립니다.

let arr = [1,2,3,4,5]

for(let i = 0; i < arr.length; i++){
console.log(arr[i]);
}

그런데 JS에서는 Array뿐만 아니라, String, Map, Set 등의 객체도 반복문을 돌 수 있습니다.

( 물론 이것은 JS만의 문법은 아닙니다. )


Array 외에 다른 객체들이 반복문을 돌 수 있는 이유는 Iteration의 구성요소를 통해 확인할 수 있습니다.

Iteration에는 Iterable과 Iterator가 존재하며, 이 두 프로토콜이 모두 존재해야 Iteration을 수행할 수 있습니다.

  • Iterable
    • Iterable는 객체가 반복될 수 있는지, 즉 반복될수 있는 조건(?)을 말합니다.
    • 그 조건으로는 객체에 Symbol.iterator가 존재해야 합니다.
      • 그런데 어떤 객체에 Symbol.iterator가 없음에도 Iterable 할 수 있는데요, prototype chain에 의해서 부모에 Symbol.iterator가 존재하면 그 객체는 Iterable 합니다. ( prototype chain - 참고 )
  • Iterator
    • 반복 대상이 되는 객체의 원소가 순서대로 불려진다는 약속을 의미합니다.
    • 즉, Iterable한 객체가 순서대로 열거될 수 있는지를 의미합니다.

위의 두 프로토콜이 만족되면 해당 객체는 Iteration을 수행할 수 있습니다.





2. for in과  for of 비교

for in과 for of는 반복이 가능한 객체의 모든 원소를 하나씩 추출하여 변수에 담아 반복문을 수행하는 문법입니다.

기본 사용법은 아래와 같습니다.

// 1. for in
for(let value in arr){
console.log(value)
}

// 1. for of
for(let value of arr){
console.log(value)
}

그런데 이 둘은 반복하는 대상에 대한 차이점이 있습니다.

  • for in 반복 대상
    • Iterable object이면 모두 반복할 수 있는 대상이 됩니다.
  • for of 반복 대상
    • Iterable object이지만, prototype chain에 의한 Iterable은 반복 대상에서 제외됩니다.

Array.prototype.foo = function(){
return 1000
}
let arr = [1,2,3,4,5]

// 1. for in
console.log("[ for in ]")
for(let value in arr){
console.log(value + " " + arr[value])
}


// 2. for of
console.log("[ for of ]")
for(let value of arr){
console.log(value)
}


Array 객체에 prototype으로 foo 함수를 추가했으므로, arr 배열에는 foo 메서드가 추가된 상태입니다.

이 상황에서 for infor of로 반복문을 수행한 결과는 위의 사진과 같습니다.



차이점

  • 1. foo 함수를 호출하는가?
    • for in
      • for in은 iterable object라면 모두 반복의 대상이 됩니다.
      • prototype chain에 의해서 Array 객체가 foo 함수를 갖기 때문에 foo함수가 반복의 대상이 된 것입니다.
    • for of
      • 반면 for of는 prototype chain에 의한 프로퍼티는 신경쓰지 않습니다.
      • 따라서 순수한 arr배열의 원소만 출력합니다.
  • 2. 변수의 값이 다르다.
    • for in
      • arr 배열의 각 원소를 임시 변수로 담을 value에는 몇 번 째 반복되고 있는지 index가 담겨있습니다.
    • for of
      • 반면 for of에서 value에는 실제 원소의 값만 순서대로 담깁니다.


개발을 하다보면 for of와 for in의 차이점으로 인하여 원하는 결과를 얻지 못할 때가 있습니다.

for offor in의 결과가 달랐던 것은 이처럼 Itertation, prototype chain과 관련이 있습니다.





3. Object 객체를 반복하기

Iterable한 객체들은 반복문을 돌 수 있다는 것을 앞에서 확인했습니다.

그런데 Object 객체 같이 Iterable object가 아닌 경우는 for of로 반복할 수 없습니다.

let foo = {
name : "victolee",
age : 25
}

for(let value of foo){
console.log(value)
}


위의 예제를 실행하면 "foo는 iterable이 아니다"는 에러가 출력됩니다.


이 객체를 반복문으로 출력하고 싶으면 어떻게 해야할까요?

let foo = {
name : "victolee",
age : 25
}
let goo = Object.keys(foo);
console.log(goo)


for(let value of goo){
console.log(value, foo[value])
}


Object.keys( ) 메서드는 매개변수 object의 프로퍼티를 배열로 반환하는 함수입니다.

따라서 goo 변수에는 ["name", "age"]가 담겨있습니다.


Object.keys() 메서드로 인해 goo 변수는 배열이 되었으므로 Iterable object입니다.

그래서 for of가 가능하며, 각 원소는 foo 객체의 프로퍼티입니다.


따라서 foo 객체의 프로퍼티 값을 구하려면 foo[value] 를 작성하면 됩니다.

참고로 foo.value는 undefined가 반환됩니다.



물론 for in으로도 구현이 가능합니다.

let foo = {
name : "victolee",
age : 25
}

for(let value in foo){
console.log(value, foo[value])
}





이상으로 Iteration과 for in과 for of의 차이점에 대해 알아보았고, 이를 정리하면 다음과 같습니다.

  • Iteration
    • Iterable
      • Symbol.iterator
    • Iterator
  • for in과 for of
    • Iterable 객체 중 prototype chain이 Iterable한 것을 포함하면 for in, 그렇지 않으면 for of 입니다.
  • Object.keys()
    • Iterable 하지 않은 객체들 Iterable하게 만들어 반복문 사용