Iterator가 javascript에서 작동하는 방식

"반복"이라는 용어는 "반복"또는 "다시 수행"을 의미하는 라틴어 itero에서 파생됩니다. 소프트웨어의 맥락에서 "반복"은 일반적으로 종료를 예상하여 절차를 순서대로 여러 번 반복적으로 수행하는 것을 의미합니다.

let sum = 0;
for(let i of [1,2,3]) { // Loop once for each of these values
    sum += i;
}
sum   // => 6


반복자는 ... 연산자와 함께 사용하여 반복 가능한 객체를 배열 이니셜라이저 또는 함수 호출로 확장하거나 "확산"할 수 있습니다.

let chars = [..."abcd"]; // chars == ["a", "b", "c", "d"]
let data = [1, 2, 3, 4, 5];
Math.max(...data)        // => 5

//Iterators can be used with destructuring assignment:

let purpleHaze = Uint8Array.of(255, 0, 255, 128);
let [r, g, b, a] = purpleHaze; // a == 128



Map 개체를 반복할 때 반환되는 값은 [key, value] 쌍이며 for/of 루프에서 구조 분해 할당과 잘 작동합니다.

let m = new Map([["one", 1], ["two", 2]]);
for(let [k,v] of m) console.log(k, v); // Logs 'one 1' and 'two 2'
If you want to iterate just the keys or just the values rather than the pairs, you can use the keys() and values() methods:

[...m]            // => [["one", 1], ["two", 2]]: default iteration
[...m.entries()]  // => [["one", 1], ["two", 2]]: entries() method is the same
[...m.keys()]     // => ["one", "two"]: keys() method iterates just map keys
[...m.values()]   // => [1, 2]: values() method iterates just map values



반복자의 작동 방식

for/of 루프 및 스프레드 연산자는 반복 가능한 객체와 원활하게 작동하지만 반복 작업을 수행하기 위해 실제로 어떤 일이 발생하는지 이해하는 것이 좋습니다.

JavaScript에서 반복을 이해하기 위해 이해해야 하는 세 가지 유형이 있습니다. 첫째, 반복 가능한 객체가 있습니다. 이들은 반복할 수 있는 Array, Set 및 Map과 같은 유형입니다. 둘째, 반복을 수행하는 반복자 개체 자체가 있습니다. 셋째, 반복의 각 단계의 결과를 보유하는 반복 결과 객체가 있습니다.

반복 가능한 객체는 반복자 객체를 반환하는 특수한 반복자 메서드가 있는 모든 객체입니다. 반복자는 반복 결과 객체를 반환하는 next() 메서드가 있는 모든 객체입니다.

그리고 반복 결과 객체는 value 및 done이라는 속성을 가진 객체입니다. 반복 가능한 객체를 반복하려면 먼저 반복자 메서드를 호출하여 반복자 객체를 가져옵니다. 그런 다음 반환된 값의 done 속성이 true로 설정될 때까지 iterator 객체의 next() 메서드를 반복해서 호출합니다.

이것에 대한 까다로운 점은 반복 가능한 객체의 반복자 메서드에 기존 이름이 없지만 Symbol Symbol.iterator를 이름으로 사용한다는 것입니다. 따라서 iterable 객체 iterable에 대한 간단한 for/of 루프는 다음과 같이 어렵게 작성할 수도 있습니다.

let iterable = [99];
let iterator = iterable[Symbol.iterator]();
for(let result = iterator.next(); !result.done; result = iterator.next()) {
    console.log(result.value)  // result.value == 99
}



내장 iterable 데이터 유형의 iterator 객체는 그 자체로 iterable입니다. (즉, 자신을 반환하는 Symbol.iterator라는 메서드가 있습니다.) 이것은 "부분적으로 사용된"반복자를 통해 반복하려는 경우 다음과 같은 코드에서 때때로 유용합니다.

let list = [1,2,3,4,5];
let iter = list[Symbol.iterator]();
let head = iter.next().value;  // head == 1
let tail = [...iter];          // tail == [2,3,4,5]



반복 가능한 객체 구현

클래스를 반복 가능하게 만들려면 이름이 Symbol Symbol.iterator인 메서드를 구현해야 합니다. 해당 메서드는 next() 메서드가 있는 반복자 개체를 반환해야 합니다. 그리고 next() 메서드는 값 속성 및/또는 부울 완료 속성이 있는 반복 결과 개체를 반환해야 합니다.

//An iterable numeric Range class

/*
 * A Range object represents a range of numbers {x: from <= x <= to}
 * Range defines a has() method for testing whether a given number is a member
 * of the range. Range is iterable and iterates all integers within the range.
 */
class Range {
    constructor (from, to) {
        this.from = from;
        this.to = to;
    }

    // Make a Range act like a Set of numbers
    has(x) { return typeof x === "number" && this.from <= x && x <= this.to; }

    // Return string representation of the range using set notation
    toString() { return `{ x | ${this.from} ≤ x ≤ ${this.to} }`; }

    // Make a Range iterable by returning an iterator object.
    // Note that the name of this method is a special symbol, not a string.
    [Symbol.iterator]() {
        // Each iterator instance must iterate the range independently of
        // others. So we need a state variable to track our location in the
        // iteration. We start at the first integer >= from.
        let next = Math.ceil(this.from);  // This is the next value we return
        let last = this.to;               // We won't return anything > this
        return {                          // This is the iterator object
            // This next() method is what makes this an iterator object.
            // It must return an iterator result object.
            next() {
                return (next <= last)   // If we haven't returned last value yet
                    ? { value: next++ } // return next value and increment it
                    : { done: true };   // otherwise indicate that we're done.
            },

            // As a convenience, we make the iterator itself iterable.
            [Symbol.iterator]() { return this; }
        };
    }
}

for(let x of new Range(1,10)) console.log(x); // Logs numbers 1 to 10
[...new Range(-2,2)]



클래스를 반복 가능하게 만드는 것 외에도 반복 가능한 값을 반환하는 함수를 정의하는 것이 매우 유용할 수 있습니다. JavaScript 배열의 map() 및 filter() 메서드에 대한 반복 가능 기반 대안을 고려하십시오.

// Return an iterable object that iterates the result of applying f()
// to each value from the source iterable
function map(iterable, f) {
    let iterator = iterable[Symbol.iterator]();
    return {     // This object is both iterator and iterable
        [Symbol.iterator]() { return this; },
        next() {
            let v = iterator.next();
            if (v.done) {
                return v;
            } else {
                return { value: f(v.value) };
            }
        }
    };
}

// Map a range of integers to their squares and convert to an array
[...map(new Range(1,4), x => x*x)]  // => [1, 4, 9, 16]

// Return an iterable object that filters the specified iterable,
// iterating only those elements for which the predicate returns true
function filter(iterable, predicate) {
    let iterator = iterable[Symbol.iterator]();
    return { // This object is both iterator and iterable
        [Symbol.iterator]() { return this; },
        next() {
            for(;;) {
                let v = iterator.next();
                if (v.done || predicate(v.value)) {
                    return v;
                }
            }
        }
    };
}

// Filter a range so we're left with only even numbers
[...filter(new Range(1,10), x => x % 2 === 0)]  // => [2,4,6,8,10]

좋은 웹페이지 즐겨찾기