π€ Chapter 6: λ°λ³΅κΈ° μ΄ν΄νκΈ°
π¦ λ°λ³΅κΈ° μ΄ν΄νκΈ°β
π λ°λ³΅κΈ°μ λ°λ³΅κΈ° μ 곡μβ
- λ°λ³΅κΈ°(iterator)λ λ€μκ³Ό κ°μ νΉμ§μ΄ μλ κ°μ²΄μ΄λ€.
next
λΌλ μ΄λ¦μ λ©μλλ₯Ό μ 곡νλ€.next
λ©μλλvalue
μdone
μ΄λΌλ λ κ°μ μμ±μ κ°μ§ κ°μ²΄λ₯Ό λ°ννλ€.
- λ€μ μ½λμμ
createRangeIterable
ν¨μλnext
λ©μλκ° μλ κ°μ²΄λ₯Ό λ°ννλ―λ‘ μ΄ ν¨μλ λ°λ³΅κΈ°λ₯Ό μ 곡νλ μν μ νλ€. μ΄μ²λΌ λ°λ³΅κΈ°λ₯Ό μ 곡νλ ν¨μλ₯Ό λ°λ³΅κΈ° μ 곡μ(iterable)λΌκ³ νλ€.
export const createRangeIterable = (from: number, to: number) => {
let currentValue = from;
return {
next() {
const value = currentValue < to ? currentValue++ : undefined;
const done = value === undefined;
return { value, done };
}
}
}
- λ€μμ
createRangeIterable
ν¨μκ° μ 곡νλ λ°λ³΅κΈ°λ₯Ό μ¬μ© νλ μμ΄λ€.
import { createRangeIterable } from './createRangeIterable';
const iterator = createRangeIterable(1, 3 + 1); // λ°λ³΅κΈ°λ νμ¬ λμνμ§ μλλ€.
while (true) {
const { value, done } = iterator.next();
if (done) {
break;
}
console.log(value);
}
createRangeIterable
ν¨μλ₯Ό νΈμΆν΄ λ°λ³΅κΈ°λ₯Ό μ»κ³iterator
λ³μμ μ μ₯νκ³ λ°λ³΅κΈ°λ μ΄μ²λΌ λ°λ³΅κΈ° μ 곡μλ₯Ό νΈμΆν΄μΌλ§ μ»μ μ μλ€.
π λ°λ³΅κΈ°λ μ νμνκ°?β
- λ°λ³΅κΈ° μ 곡μλ μ΄λ€ λ²μμ κ°μ νκΊΌλ²μ μμ±ν΄μ λ°°μ΄μ λ΄μ§ μκ³ κ°μ΄ νμν λλ§ μμ±νλ€.
- λ€μμ 5μ₯μ
range
ν¨μμ΄λ€.
export const range = (from, to) => from < to ? [from, ...range(from + 1, to)] : [];
createRangeIterable
ν¨μλ κ°μ΄ νμν μμ μ λΉλ‘μ μμ±νμ§λ§,range
ν¨μλ κ°μ΄ νμν μμ λ³΄λ€ μ΄μ μ 미리 μμ±νλ€. λ°λΌμ μμ€ν λ©λͺ¨λ¦¬μ ν¨μ¨μ±μ΄λΌλ κ³Όμ μμ 보면createRangeIterable
ν¨μκ° λ©λͺ¨λ¦¬λ₯Ό ν¨μ¬ μ κ² μλͺ¨νλ€.
π for...of ꡬ문과 [Symbol.iterator] λ©μλβ
- 5μ₯μ
range
ν¨μλfor...of
ꡬ문μof
λ€μ μ¬ μ μλ€.
for (let value of range(1, 3 + 1)) {
console.log(value); // 1 2 3
}
- κ·Έλ¬λ λ€μ μ½λμ²λΌ μμμ μμ±ν
createRangeIterable
ν¨μλ₯Όfor...of
ꡬ문μ μ μ©νλ©΄[Symbol.iterator]() λ©μλκ° μλ€
λ μ€λ₯κ° λ°μνλ€.
const iterable = createRangeIterable(1, 3 + 1);
for(let value of iterable) {
console.log(value);
}
- μ΄ μ€λ₯λ
createRangeIterable
ν¨μλ₯Ό λ€μRangeIterable
μ²λΌ ν΄λμ€λ‘ ꡬνν΄μΌ νλ€λ κ²μ μλ―Ένλ€. RangeIterable
ν΄λμ€λ[Symbol.iterator]
λ©μλλ₯Ό ꡬννκ³ μλ€.
class RangeIterable {
constructor(public from: number, public to: number) {};
[Symbol.iterator]() {
const that = this;
let currentValue = that.from;
return {
next() {
const value = currentValue < that.to ? currentValue++ : undefined;
const done = value === undefined;
return { value, done };
}
}
}
}
const iterator = new RangeIterable(1, 3 + 1);
for (const value of iterator) {
console.log(value); // 1 2 3
}
π Iterable<T>
μ Iterator<T>
μΈν°νμ΄μ€β
- νμ
μ€ν¬λ¦½νΈλ λ°λ³΅κΈ° μ 곡μμ
Iterable<T>
μIterator<T>
μ λ€λ¦ μΈν°νμ΄μ€λ₯Ό μ¬μ©ν μ μλ€.Iterable<T>
λ λ€μμ²λΌ μμ μ ꡬννλ ν΄λμ€κ°[Symbol.iterator]
λ©μλλ₯Ό μ 곡νλ€λ κ²μ λͺ ννκ² μλ €μ£Όλ μν μ νλ€.
class ꡬνν΄λμ€ implements Iterable<μμ±ν _κ°μ_νμ
> {}
Iterator<T>
λ λ°λ³΅κΈ°κ° μμ±ν κ°μ νμ μ λͺ ννκ² ν΄μ€λ€.
[Symbol.iterator](): Iterator<μμ±ν _κ°μ_νμ
> {}
- λ€μμ λ°λ³΅κΈ° μ 곡μλ₯Ό νμ
μ€ν¬λ¦½νΈκ° μ 곡νλ
Iterable<T>
μIterator<T>
λ₯Ό μ¬μ©ν΄ ꡬνν μμ΄λ€.
export class StringIterable implements Iterable<string> {
constructor(private strings: string[] = [], private currentIndex: number = 0) {}
[Symbol.iterator](): Iterator<string> {
const that = this;
let currentIndex = that.currentIndex;
let length = that.strings.length;
const iterator: Iterator<string> = {
next(): { value: string, done: boolean } {
const value = currentIndex < length ? that.strings[currentIndex] : undefined;
const done = value === undefined;
return { value, done };
}
}
return iterator;
}
}
for (let value of new StringIterable(['hello', 'world', '!'])) {
console.log(value); // hello world !
}
π¦ μμ±κΈ° μ΄ν΄νκΈ°β
yield
λ λ§μΉreturn
ν€μλμ²λΌ κ°μ λ°ννλ€.yield
λ λ°λμfunction*
ν€μλλ₯Ό μ¬μ©ν ν¨μμμλ§ νΈμΆν μ μλ€. μ¬κΈ°μfunction*
ν€μλλ‘ λ§λ ν¨μλ₯Ό μμ±κΈ°(generator)λΌκ³ λΆλ₯Έλ€.
export function* generator() {
console.log('start');
let value = 1;
while (value < 4) {
yield value++;
}
console.log('finish');
};
for (const value of generator()) {
console.log(value);
// start
// 1
// 2
// 3
// finish
}
π setInterval ν¨μμ μμ±κΈ°μ μ μ¬μ±β
- μμ±κΈ°κ° λμνλ λ°©μμ μΈλ―Έμ½λ£¨ν΄(semi-coroutine)μ΄λΌκ³ νλ€.
- μΈλ―Έμ½λ£¨ν΄μ νμ μ€ν¬λ¦½νΈμ²λΌ λ¨μΌ μ€λ λλ‘ λμνλ νλ‘κ·Έλλ° μΈμ΄κ° λ§μΉ λ€μ€ μ€λ λλ‘ λμνλ κ²μ²λΌ 보μ΄κ² νλ κΈ°λ₯μ νλ€.
setInterval
ν¨μλ 무νν λ°λ³΅νμ§λ§clearInterval
ν¨μλ₯Ό μ¬μ©νλ©΄ λ©μΆ μ μλ€.
const period = 1000;
let count = 0;
console.log('program started...');
const id = setInterval(() => {
if (count >= 3) {
clearInterval(id);
console.log('program finished');
} else {
console.log(++count);
}
}, period);
// program started...
// 1
// 2
// 3
// program finished...
setInterval
μ λμμν¨ λΆλΆμ΄ λ©μΈ μ€λ λ,setInterval
μ μ½λ°± ν¨μλ μμ μ€λ λλ₯Ό λ μ¬λ¦¬κ² νλ. μμ±κΈ°λ μ΄μ²λΌ μΌλ°μ μΈ νμ μ€ν¬λ¦½νΈ μ½λμλ μ’ λ€λ₯Έ λ°©μμΌλ‘ λμνλ€.
- μ½λ£¨ν΄μ μ ν리μΌμ΄μ λ 벨μ μ€λ λμ΄λ€. μ½λ£¨ν΄μ λͺ©μ μ μ΄μ체μ μ λΆλ΄μ μ£Όμ§ μμΌλ©΄μ μ ν리μΌμ΄μ μμ μ€λ λλ₯Ό λ§μκ» μΈ μ μκ² νλ κ²μ΄λ€. κ·Έλ°λ° μ½λ£¨ν΄μ μ€λ λμ΄λ―λ‘ μΌμ μ£ΌκΈ°μ λ°λΌ μλμΌλ‘ λ°λ³΅ν΄μ μ€νλλ€.
- λ°λ©΄μ μμ±κΈ°λ μ λ°λ§ μ½λ£¨ν΄μ΄λ€. μ¦, λ°λ³΅ν΄μ μ€νν μ μμ§λ§ μλμΌλ‘ μ€νλμ§ λͺ»νλ μ½λ£¨ν΄μ΄λ€. μμ±κΈ°κ° λ§λ€μ΄μ€ λ°λ³΅μμ
next
νΈμΆ λ ν λ² μ€νλκ³ κ³§λ°λ‘ λ©μΆλ€. μ΄μ²λΌ μμ±κΈ°λ μλμΌλ‘ λ°λ³΅ μ€νλμ§ μμΌλ―λ‘ μΈλ―Έμ½λ£¨ν΄μ΄λΌκ³ νλ€.
π function* ν€μλβ
generator
ν¨μμ μΌλ° ν¨μμ λ€λ₯Έμ
function*
ν€μλλ‘ ν¨μλ₯Ό μ μΈνλ€.- ν¨μ λͺΈν΅ μμ
yield
λ¬Έμ΄ μλ€.
- μ¦,
function*
ν€μλλ‘ μ μΈλ ν¨μκ° μμ±κΈ°μΈλ°, μμ±κΈ°λ μ€μ§function*
ν€μλλ‘ μ μΈν΄μΌ νλ―λ‘ νμ΄ν ν¨μλ‘λ μμ±κΈ°λ₯Ό λ§λ€ μ μ μ³.
π yield ν€μλβ
- μμ±κΈ° ν¨μ μμλ
yield
λ¬Έμ μ¬μ©ν μ μλ€.yield
λ μ°μ°μ ννλ‘ λμνλ©° λ€μμ²λΌ λ κ°μ§ κΈ°λ₯μ νλ€.
- λ°λ³΅κΈ°λ₯Ό μλμΌλ‘ λ§λ€μ΄ μ€λ€.
- λ°λ³΅κΈ° μ 곡μ μν λ μννλ€.
export function* rangeGenerator(from: number, to: number) {
let value = from;
while(value < to) {
yield value++;
}
}
let iterator = rangeGenerator(1, 3 + 1);
while (1) {
const { value, done } = iterator.next();
if (done) {
break;
}
console.log(value); // 1 2 3
}
for (const value of rangeGenerator(4, 6 + 1)) {
console.log(value); // 4 5 6
}
π λ°λ³΅κΈ° μ 곡μμ λ©μλλ‘ λμνλ μμ±κΈ° ꡬνβ
StringIterable
ν΄λμ€λ₯Ό μμ±κΈ°λ₯Ό μ¬μ©νλ©΄ κ°κ²°νκ² κ΅¬νν μ μλ€.
export class IterableUsingGenerator implements Iterable<string> {
constructor(private values: string[] = [], private currentIndex: number = 0) {}
[Symbol.iterator] = function* () {
while(this.currentIndex < this.values.length) {
yield this.values[this.currentIndex++];
}
}
}
for (const item of new IterableUsingGenerator([1, 2, 3])) {
console.log(item);
}
for (const item of new IterableUsingGenerator(['hello', 'world', '!'])) {
console.log(item);
}
π yield* ν€μλβ
yield*
λ λ€λ₯Έ μμ±κΈ°λ λ°°μ΄μ λμμΌλ‘ λμνλ€.
function* gen12() {
yield 1;
yield 2;
}
export function* gen12345() {
yield* gen12();
yield* [3, 4];
yield 5;
}
π yield λ°νκ°β
yield
μ°μ°μλ κ°μ λ°ννλ€.
export function* gen() {
let count = 5;
let select = 0;
while(count--) {
select = yield `you select ${select}`;
}
}
export const random = (max, min = 0) => Math.round(Math.random() * (max - min)) + min;
yield
μ°μ°μμ λ°νκ°μ λ°λ³΅κΈ°μnext
λ©μλ νΈμΆ λ 맀κ°λ³μμ μ λ¬νλ κ°μ΄λ€.next
λ©μλ νΈμΆ λ λμλ₯Ό μμ±ν΄ μ λ¬νλ€.
const iter = gen();
while(true) {
const { value, done } = iter.next(random(10, 1));
if(done) {
break;
}
console.log(value);
// you select 0
// you select 3
// you select 9
// you select 2
// you select 9
}
- μ€ν κ²°κ³Όλ μ΄μ μ
next
λ©μλκ° μ λ¬ν κ°μ΄ λ€μgen
ν¨μμ λ΄λΆ λ‘μ§μ μν΄ νμ¬μvalue
κ°μ΄ λμ΄ μΆλ ₯λλ€.