Junhyunny's Devlogs

글 검색

기술 글 제목, 본문, 카테고리에서 검색합니다.

    이전 화면으로

    자바스크립트 for-of 반복문

    • javascript
    이 글의 목차

    0. 들어가면서

    JavaScript로 for 반복문을 작성하다 보면 헷갈리는 문법이 있다.

    • for-of
    • for-in

    매번 찾아보거나 테스트 코드를 통해 미리 실행해보는 식으로 작업했다. 간략하게라도 정리하면 한동안 사용 기준을 잊지 않을 것 같아서 간단하게 포스트로 작성하였다. 먼저 for-of 반복문에 대해 살펴보겠다.

    1. Iterable Object

    The for…of statement executes a loop that operates on a sequence of values sourced from an iterable object.

    for-of 루프(loop)는 반복 가능 객체(iterable object)로부터 순차적으로 값을 사용하는 방식이다. 먼저 반복 가능 객체에 대해 살펴보겠다.

    • 반복 가능 객체는 ES2015에 도입되었으며 객체 속성 중 Symbol.iterator라는 특별한 함수가 존재한다.
    • Symbol.iterator 함수를 가진 객체는 이터러블 프로토콜(iterable protocol)을 만족한다고 표현한다.
      • 프로토타입(prototype) 객체를 통해 상속받는 경우도 포함된다.
    • 다시 말해 이터러블 프로토콜을 만족하는 객체는 반복 가능 객체이다.
    • 대표적으로 다음과 같은 객체들이 존재한다.
      • Array, String, TypedArray, Map, Set, NodeList

    2. for-of Loop Example

    간단한 코드를 통해 동작을 살펴보겠다.

    • array 배열 객체 순환
      • 배열에 담긴 문자열이 순차적으로 출력된다.
    • map 맵 객체 순환
      • 맵에 담긴 엔트리(entry)가 순차적으로 출력된다.
      • 출력된 엔트리는 배열 객체이다.
    • object 객체 순환
      • Uncaught TypeError 에러가 발생한다.
      • object is not iterable 에러 메시지가 출력된다.
      • 일반 객체는 이터러블 프로토콜을 만족하지 못하기 때문에 에러가 발생한다.
    const array = ['1', '2', 'Hello World'];
    
    for(const item of array) {
        console.log(item); // 1, 2, Hello World
    }
    
    const map = new Map();
    map.set('foo', 'foo hello world');
    map.set('bar', 'bar hello world');
    
    for(const item of map) {
        console.log(item); // ['foo', 'foo hello world'], ['bar', 'bar hello world']
    }
    
    const object = {
        foo: 'foo hello world',
        bar: 'bar hello world',
    };
    
    for(const item of object) {
        console.log(item); // Uncaught TypeError: object is not iterable
    }

    3. Make Iterable Object

    이터러블 프로토콜을 만족하는 객체는 반복 가능 객체이다. 마찬가지로 일반 객체라도 이터러블 프로토콜을 만족하게 만든다면 반복 가능 객체로 만들 수 있다. 아래 코드처럼 반복 불가능한 객체라 에러가 발생한 상황을 변경해보겠다.

    const object = {
        0: 'W',
        1: 'o',
        2: 'r',
        3: 'l',
        4: 'd',
        5: '!'
    };
    
    for(const item of object) {
        console.log(item); // Uncaught TypeError: object is not iterable
    }

    3.1. Iterator Protocol

    Symbol.iterator 함수는 이터레이터(iterator) 객체를 반환한다. 이터레이터 객체는 다음과 같은 조건을 만족하는 객체이다.

    • next 메서드를 갖는다.
    • next 메서드는 다음 두 속성을 갖는 객체를 반환한다.
      • done 속성 - 반복 완료 여부
      • value 속성 - 현재 순서의 값
    • 이런 조건을 이터레이터 프로토콜(iterator protocol)을 만족했다고 표현한다.

    3.2. Define Symbol.iterator Function

    이터레이터 객체를 반환하는 Symbol.iterator 함수를 선언하고 코드를 실행해보겠다.

    • Symbol.iterator 함수는 객체를 반환한다.
      • position 속성 - 현재 가리키는 값의 위치 정보
      • end 속성 - 마지막 위치 정보
      • next 함수 - 이터레이터 객체를 반환하는 함수
    • next 함수는 다음과 같은 동작을 수행한다.
      • 현재 위치가 마지막 위치 이하인 경우
        • done 속성 - 미완료 상태
        • value 속성 - 현재 포지션의 값
        • this.position++ 코드를 통해 현재 포지션을 다음 포지션으로 이동
      • 현재 위치가 마지막 위치를 초과하는 경우
        • done 속성 - 완료 상태
        • value 속성 - 마지막 포지션의 값
    const object = {
        0: 'W',
        1: 'o',
        2: 'r',
        3: 'l',
        4: 'd',
        5: '!',
        from: 0,
        to: 5
    };
    
    object[Symbol.iterator] = function () {
        return {
            position: object.from,
            end: object.to,
            next() {
                if(this.position <= this.end) {
                    return {done: false, value: object[this.position++]};
                }
                return {done: true, value: object[this.position]};
            }
        };
    };
    
    for(const item of object) {
        console.log(item); // W, o, r, l, d, !
    }

    KEEP READING

    DISCUSSION

    댓글