Javascript Array는 iterable 하다.
let names = ["Flynn", "Hanna", "Dain"];
for(let name of names) {
console.log(name);
}
Javascript Plain Object는 iterable 하지 않다.
let post = {
title: 'Iterators ES2015',
comments: 101
};
for(let p of post) {
console.log(p);
}
// TypeError:post[Symbol.iterator] is not a function
iterable은 iterator object를 반환한다. iterator object는 컬렉션에 한번에 하나의 아이템에 접근하는 방법과 순서간의 현재 위치 정보를 알고 있다.
let names = ["Flynn", "Hanna", "Dain"];
for(let name of names) {
console.log(name);
}
// behind the scenes
let iterator = names[Symbol.iterator]();
let firstRun = iterator.next();
// { done: false, value: 'Flynn' }
let name = firstRun.value;
let secondRun = iterator.next();
// { done: false, value: 'Hanna' }
let name = secondRun.value;
let thirdRun = iterator.next();
// { done: false, value: 'Dain' }
let name = thirdRun.value;
let fourthRun = iterator.next();
// { done: true, value: undefined }
**done(boolean)**은 컬렉션의 리턴할 value가 있는 경우 false
컬렉션이 종료된 경우 true
**value(any)**는 컬렉션의 리턴하는 값 컬렉션 순회가 끝나면 undefined
let post = {
title: 'Iterators ES2015',
comments: 101
};
post[Symbol.iterator] = function() {
let next = () => {}
return {next};
}
for(let p of post) {
console.log(p);
}
// Cannot read property 'done' of undefined
...
post[Symbol.iterator] = function() {
let properties = Object.keys(this);
let count = 0;
let isDone = false;
let next = () => {
if(count >= properties.length) {
isDone = true;
}
return {
done: isDone,
value: this[properties[count++]]
};
}
return {next};
}
for(let p of post) {
console.log(p);
}
iterable protocol 을 제공하면 spread operator를 사용 할 수 있다.
let values = [...post];
console.log(values); // ['Iterators ES2015', 100]
iterable protocol 을 제공하면 destructuring assignment를 사용 할 수 있다.
let [title, comments] = post;
console.log(title); // Iterators ES2015
console.log(comments); // 100
**Generator**를 사용해서 리팩토링
// Generator function signiture
post[Symbol.iterator] = function *() {
let properties = Object.keys(this);
for(let p of properties) {
yield this[p];
}
}
// same
post[Symbol.iterator] = function *() {
yield this.title;
yield this.comments;
}