[JavaScript] iterable

mechaniccoder·2020년 11월 20일
0
post-thumbnail

iterable이란?

iterable은 말 그대로 반복 가능한 객체를 의미합니다. 대표적으로 배열, 문자열 등등이 있습니다. 이러한 개념을 활용하면 어떤 객체든 iterable하게 만들 수 있습니다.

iterable 객체 만들기

iterable한 객체를 만들기 위해서는 Symbol.iterator 메서드를 활용합니다. 객체는 이를 가지고 있어야하죠. 아래에 코드를 확인하세요.

const range = {
    from: 1,
    to: 5
}

// for ... of가 시작되면 Symbol.iterator를 호출합니다. 
range[Symbol.iterator] = function() {
    // Symbol.iterator는 iterator 객체를 반환하고요. for ... of는 이 iterator객체만을 대상으로 동작합니다.
    return {
        current: this.from,
        last: this.to,

        // for ... of의 반복마다 next가 호출됩니다.
        next() {
            if (this.current <= this.last) {
                return {done: false, value: this.current++}
            } else {
                return {done: true}
            }
        }
    }
}

for (num of range) {
    console.log(num); // 1, 2, 3, 4, 5
}

for ... of 문법은 Symbol.iterator 메서드가 반환한 iterator를 대상으로 순회합니다. 각 반복마다 next 메서드를 호출하구요. 만약 Symbol.iterator가 없으면 iterable 객체가 아니기 때문에 반복문을 사용할때 에러가 납니다. 주의하세요!!

자기 자신을 iterator로 만들기

자기 자신을 iterator로 만들어주면 코드가 한결 더 편안해집니다. 아래 코드를 확인하세요.

const range = {
    from: 1,
    to: 5,

    [Symbol.iterator]() {
        this.current = this.from;
        // 이렇게 iterator를 자기 자신으로 설정하면 코드가 훨씬 간결해집니다.
        return this; // for ... of가 range.[Symbol.iterator]를 호출하면 this = range가 되겠죠.
    },

    next() {
        if (this.current <= this.to) {
            return { done: false, value: this.current++}
        } else {
            return { done: true }
        }
    }
}

for (num of range) {
    console.log(num);
}

명시적 iterable의 활용

자 그럼 이를 활용해서 우리는 반복되는 iterable한 객체를 조금 더 분해할 수 있습니다. 아래 코드처럼요.

const str = 'seo';

// iterator객체를 할당해서 조금 더 명시적으로 반복문을 제어할 수도 있습니다.
const iterator = str[Symbol.iterator]();

while(true) {
    let result = iterator.next();
    if (result.done) break;

    console.log(result.value);
}

iterable vs 유사배열

헷갈리지 마세요. 유사배열은 length index 프로퍼티를 가진 객체를 의미합니다. Symbol.iterator를 가지고 있지 않기 때문에 반복문을 사용할 수 없습니다.

또한 iterable과 유사배열 둘 다 엄밀히 따지면 배열은 아니기 때문에 배열 메서드를 사용할 수 없어요. 만약 배열 메서드를 사용하고 싶으면 Array.from을 사용해 배열로 변환해주세요.

/**
 * index와 length 프로퍼티가 있으면 이를 '유사배열' 이라고 합니다.
 * 유사배열과 iterable은 엄연히 다릅니다. 유사배열엔 [Symbol.iterator] 메소드가 정의되어있지 않죠?
 * 그리고 둘 다 배열은 아니기 때문에 배열 메소드를 활용할 수 없습니다. 
 * */ 
const arrayLike = {
    0: 'hello',
    1: 'world', 
    length: 2
}

for (let item of arrayLike) {
    console.log(item); // TypeError: arrayLike is not iterable
}

// 유사배열과 iterable을 배열로 활용하기 위해서는 Array.from을 사용하면 됩니다.
const array = Array.from(arrayLike);
console.log(array); // [ 'hello', 'world' ]

정리

오늘 iterable에 대해서 알아봤는데요. Symbol.iterator가 있어야 iterable객체인 것을 알았죠. 되게 간단하지만 이제 javascript 공부를 시작하신 분들은 몰랐을 거라 생각해요. 이 글이 도움이 되셨으면 좋겠습니다.

profile
세계 최고 수준을 향해 달려가는 개발자입니다.

0개의 댓글