반복 가능한 객체를 다루기 위해 사용되는 iterator(반복자)
입니다. iterator
는 일련의 값을 순차적으로 반환할 수 있는 객체입니다. 이 객체는 next()
메소드를 가지며, 각 호출마다 값을 가진 객체를 반환합니다. 반환되는 객체는 {value, done}
입니다. value
는 현제 반복 위치의 값이고, done
은 반복이 완료 되었는지를 나타내는 boolean
값입니다.
iterable(반복 가능한) 객체는 ‘Symbol.iterator’
라는 특별한 메소드를 구현해 Iterator
객체를 반환합니다.
const arr = [1,2,3]
const iterator = arr[Symbol.iterator]();
console.log(iterator.next()}; // { value : 1, done: false }
console.log(iterator.next()}; // { value : 2, done: false }
console.log(iterator.next()}; // { value : 3, done: false }
console.log(iterator.next()}; // { value : undefined, done: true }
위 예시에서는 arr[Symbol.iterator]()
를 호출하여 배열 arr의 iterator객체를 얻습니다. 그리고 iterator.next()
를 호출하여 iterator객체를 통해 순차적으로 값을 얻습니다. done의 참 거짓 여부를 통해 반복문이 완료됨을 알수도 있습니다.
for…of
를 사용해 Iterator루프를 편리하게 사용할 수 있습니다. for…of 루프는 자동으로 Iterable객체의 Iterator를 가져와 값을 반복합니다.
const arr = [1,2,3]
for(const value of arr){
console.log(value);
}
각 요소를 순회하면서 value에 값을 할당하여 출력합니다.
임의 숫자를 인자로 받고 그 값으로 이터레터를 만드는 편리함 함수를 만들고 싶다고 가정해봅시다.
var it = values(1,2,3,4,5,6,3,4) ;
it.next(); //1
it.next(); //2
it.next(); //3
it.next(); //4
values 함수는 인자가 몇개인지 관계없이 모두 받아들일 수 있어야 하므로 arguments 객체의 요소들을 열거하기 위해 다음과 같은 iterator 객체를 만들 것입니다.
function values(){
var i = 0, n = arguments.length;
return{
haseNext:function(){
return (i < n)
},
next:function(){
if(i>=n){
throw new Error("end of iterator");
}else{
return arguments[i++];//잘못된 arguments
}
}
}
}
다음 코드는 잘 못되었습니다. 실제로 실행해 보면
var it = values(1,2,3,4,5,6,3,4) ;
it.next(); // undefined
it.next(); // undefined
it.next(); // undefined
it.next(); // undefined
문제는 각 함수의 본문에서 새로운 arguments 변수가 암묵적으로 바인딩 된것이 문제 입니다. 이게 무슨 소리냐면 next 함수에서 사용된 arguments는 values함수의 arguments가 아니라 next의 arguments로 암묵적으로 바인딩 되었다는 말입니다.
내가 사용할 arguments 객체를 지역변수에 담아 명시적으로 어느 arguments를 사용하는지 확실히 하면 됩니다.
function values(){
var i = 0, n = arguments.length; **a = arguments**
return{
haseNext:function(){
return (i < n)
},
next:function(){
if(i>=n){
throw new Error("end of iterator");
}else{
return **a[i++]**;
}
}
}
}
var it = values(1,2,3,4,5,6,3,4) ;
it.next(); //1
it.next(); //2
it.next(); //3
it.next(); //4