λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ’» DEV/Javascript & NodeJS

[Javascript] Iterable (μ΄ν„°λŸ¬λΈ”)

by vodkassi 2021. 10. 13.
728x90

πŸ“ Intro

Iterate λŠ” 'λ°˜λ³΅ν•˜λ‹€' λŠ” 사전적 의미λ₯Ό 가지고 μžˆλŠ” μš©μ–΄λ‘œ, ν”„λ‘œκ·Έλž˜λ°μ—μ„œλŠ” 주둜 '반볡 κ°€λŠ₯ν•œ 객체' λ₯Ό μ˜λ―Έν•œλ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈμ—λ§Œ μ‘΄μž¬ν•˜λŠ” κ°œλ…μ€ μ•„λ‹ˆμ§€λ§Œ, μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ μ΄ν„°λŸ¬λΈ” κ°œλ…μ„ ν•™μŠ΅ν•˜λ©΄ λ‹€λ₯Έ ν”„λ‘œκ·Έλž˜λ° μš©μ–΄μ—λ„ μ‰½κ²Œ μ μš©ν•  수 μžˆλ‹€. 

 

✨  ES6 에 μΆ”κ°€λœ Iterable

ECMAScript λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό ν‘œμ€€ν™”ν•˜κ³  ν† λŒ€λ₯Ό κ΅¬μ„±ν•˜κΈ° μœ„ν•΄ λ§Œλ“€μ–΄μ§„ ν‘œμ€€ν™”λœ 슀크립트 ν”„λ‘œκ·Έλž˜λ° 언어이며, ES6은 6번째 ECMAScript 버전을 μ˜λ―Έν•œλ‹€. ES6 은 2015년에 μ œμ •λ˜μ—ˆλŠ”λ°, μ΄μ „κΉŒμ§€ λ¬Έμ œκ°€ λ˜μ—ˆλ˜ λ§Žμ€ 뢀뢄듀이 ν•΄κ²°λ˜κ³  κΈ°λŠ₯이 λŒ€κ±° μΆ”κ°€λ˜μ–΄ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ 가독성과 μœ μ§€λ³΄μˆ˜μ„±μ„ ν–₯μƒν–ˆλ‹€.

 

ES6μ—λŠ” 기쑴에 μ—†μ—ˆλ˜ Scope, parameter handling, ꡬ쑰뢄해 ν• λ‹Ή λ“± JS κ°œλ°œμžλ“€μ΄ ν”νžˆ μ‚¬μš©ν•˜λŠ” μ—¬λŸ¬ κ°œλ…λ“€μ΄ λ„μž…λ˜μ—ˆλ‹€. 이 λ•Œ ν•¨κ»˜ λ„μž…λœ 것이 λ°”λ‘œ Iterable κ³Ό Iterator λ₯Ό κ΄„λͺ©ν•˜λŠ” Iteration Protocol 이닀. 

 

❗ES6 μ΄μ „μ—λŠ” iteration protocol 없이도 λ°°μ—΄, λ¬Έμžμ—΄ 등을 for, while λ¬Έκ³Ό 같은 반볡문으둜 μˆœνšŒν•  수 μžˆμ—ˆλ‹€. ES6에 λ“€μ–΄μ„œλ©° μ΄λŸ¬ν•œ λ°˜λ³΅ν˜• κ°μ²΄λ“€μ˜ ν”„λ‘œν† μ½œμ΄ ν†΅μΌλ˜κ³ , μ—¬λŸ¬ λ©”μ„œλ“œμ˜ 곡톡 λŒ€μƒμ΄ 될 수 μžˆλ„λ‘ ν•œ 것이닀. 

 

✨  Iteration Protocol 

Iteration protocol μ•ˆμ—λŠ” Iterable protocol κ³Ό Iterator protocol 이 μ‘΄μž¬ν•œλ‹€. 

 

Symbol.iterator λ₯Ό ν”„λ‘œνΌν‹° ν‚€λ‘œ μ‚¬μš©ν•œ λ©”μ„œλ“œλ₯Ό 직접 κ΅¬ν˜„ν•˜κ±°λ‚˜, ν”„λ‘œν† νƒ€μž… 체인을 톡해 μƒμ†ν•˜μ—¬ ν˜ΈμΆœν•¨μœΌλ‘œμ¨ iteratorλ₯Ό λ°˜ν™˜ν•˜λŠ” κ·œμ•½μ΄ πŸ’‘Iterable protocol이닀. 이 λ•Œ, iterable protocol 을 μ€€μˆ˜ν•œ κ°μ²΄λŠ” iterable 이라고 ν•œλ‹€. (for.. of, spread, rest 문법 λŒ€μƒμ΄ 됨) Iterable 의 Symbol.iterator λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ iterator λ₯Ό λ°˜ν™˜ν•˜λŠ”λ°,  이 iterator λŠ” πŸ’‘Iterator protocol λ₯Ό μ€€μˆ˜ν•œλ‹€ (next method, value property, done property μ†Œμœ ). Iterator λŠ” iterable 의 μš”μ†Œλ₯Ό νƒμƒ‰ν•˜κΈ° μœ„ν•œ 포인터 역할을 ν•œλ‹€. 

 

말이 μ–΄λ ΅κ³  μ€‘λ³΅λ˜λŠ” λ‚΄μš©μ΄ λ§Žμ•„ 보일 것이닀. λ‚΄μš©μ„ μ°¨λ‘€λ‘œ μ‚΄νŽ΄λ³΄λ©° μ–΄λ–»κ²Œ λ‹€λ₯Έ 것인지 μ‚΄νŽ΄λ³΄μž. 

 

❗ ν•˜μ§€λ§Œ κ·Έ 전에 μš°μ„  Symbol.iterator 에 λŒ€ν•œ 이해가 ν•„μš”ν•˜λ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈμ—λŠ” 빌트인 Symbol ν•¨μˆ˜κ°€ μžˆλ‹€. 이 Symbol ν•¨μˆ˜ μ•ˆμ—λŠ” 빌트인 μ‹¬λ²Œλ“€μ΄ ν”„λ‘œνΌν‹°λ‘œ ν• λ‹Ήλ˜μ–΄ 있으며, 이듀을 Well-known Symbol 이라고 λΆ€λ₯Έλ‹€. 이 쀑 ν•˜λ‚˜μΈ Symbol.iterator μ—­μ‹œ 빌트인 μ‹¬λ²Œμ΄λ‹€.

 

Iterable protocol을 λ”°λ₯΄λŠ” 객체 (Iterable) λŠ” λ‹€μŒκ³Ό 같은 νŠΉμ§•μ„ κ°–λŠ”λ‹€. 

1. Symbol.iterator λ₯Ό ν”„λ‘œνΌν‹° ν‚€λ‘œ μ‚¬μš©ν•œ λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•œλ‹€

2. Symbol.iterator λ₯Ό ν”„λ‘œν† νƒ€μž… 체인을 톡해 μƒμ†λ°›λŠ”λ‹€ 

 

그리고 Iterator protocol 을 λ”°λ₯΄λŠ” 객체 (iterator) λŠ” λ‹€μŒκ³Ό 같은 νŠΉμ§•μ„ κ°–λŠ”λ‹€. 

3. next λ©”μ„œλ“œ μ†Œμœ 

4. next λ©”μ„œλ“œμ˜ κ²°κ³Ό 객체에 done, value ν”„λ‘œνΌν‹°λ₯Ό μ†Œμœ 

 

λ‹€μŒ μ˜ˆμ‹œκ°€ μœ„μ˜ λ‚΄μš©μ„ λͺ…μΎŒν•˜κ²Œ μ •λ¦¬ν•œλ‹€. 

 

const test = {
    [Symbol.iterator]() {
        let cur = 1;
        const max = 5;
        return {
            next() {
                return {value: cur++, done: cur > max + 1}
            }
        }
    }
}

 

μœ„μ˜ test κ°μ²΄λŠ” Symbol.iterator λ₯Ό ν”„λ‘œνΌν‹° ν‚€λ‘œ μ‚¬μš©ν•˜μ—¬, λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜κ³  있기 λ•Œλ¬Έμ— (1번 νŠΉμ§•) iterable protocol 을 μ€€μˆ˜ν•œλ‹€. λ”°λΌμ„œ test κ°μ²΄λŠ” 곧 iterable 이닀. 

 

λ˜ν•œ, test μ•ˆμ— κ΅¬ν˜„λœ Symbol.iterator λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•˜λ©΄ iterator κ°€ λ°˜ν™˜μ΄ λ˜λŠ”λ°, 이 iterator λŠ” next λ©”μ„œλ“œλ₯Ό 가지며 (3번 νŠΉμ§•), next() 의 μ‹€ν–‰ 결과에 value 와 done ν”„λ‘œνΌν‹°λ₯Ό κ°–λŠ”λ‹€ (4번 νŠΉμ§•). 

 

for (let num of test){
    console.log(num) // 1 2 3 4 5
}

let it = test[Symbol.iterator]();
it.next() // {value: 1, done: false}
it.next() // {value: 2, done: false}
it.next() // {value: 3, done: false}
it.next() // {value: 4, done: false}
it.next() // {value: 5, done: true}

 

μœ„μ˜ μ˜ˆμ‹œμ— λ‚˜μ˜¨ next λ©”μ„œλ“œλŠ” iterable 의 각 μš”μ†Œλ₯Ό μˆœνšŒν•˜κΈ° μœ„ν•œ 포인터 역할을 ν•œλ‹€. 그리고 순회의 결과둜 λ‚˜μ˜€λŠ” 객체λ₯Ό iterator result object 라고 μΉ­ν•œλ‹€. 

 

πŸ’‘ μ •λ¦¬ν•˜μžλ©΄, iterator λ₯Ό λ°˜ν™˜ν•˜λŠ” λ©”μ„œλ“œλ₯Ό κ°–λŠ” 객체λ₯Ό iterable 이라고 ν•˜λ©°, μ΄λŸ¬ν•œ iterable 은 iteration protocol 을 μ€€μˆ˜ν•œλ‹€. 

 

 

μš°λ¦¬κ°€ ν”νžˆ μ•„λŠ” Array, String, Map, Set λ“±μ˜ 객체듀은 λͺ¨λ‘ 빌트인 (λ‚΄μž₯된) iterable 이며, μœ„μ˜ μ˜ˆμ‹œμ²˜λŸΌ μƒˆλ‘­κ²Œ λ§Œλ“  객체듀도 λͺ¨λ‘ iterable 이닀. μ–΄λ– ν•œ 객체가 iterable 인지 μ—¬λΆ€λ₯Ό ν™•μΈν•˜κ³ μž ν•œλ‹€λ©΄ λ‹€μŒκ³Ό 같은 방법을 μ‚¬μš©ν•˜λ©΄ λœλ‹€. (λ‹€μŒ μ˜ˆμ‹œμ—μ„œλŠ” Array.prototype 의 Symbol.iterator λ©”μ„œλ“œλ₯Ό 상속받은 배열을 μ‚¬μš©ν•œλ‹€) 

 

// 방법 1 : 객체 내뢀에 Symbol.iterator λ₯Ό ν‚€λ‘œ κ°–λŠ” λ©”μ„œλ“œ μžˆλŠ”μ§€ 확인 

const iter = [];
iter[Symbol.iterator] // ƒ values() { [native code] }

// 방법 2 : 객체의 key κ°’ 직접 확인
Symbol.iterator in []; // true

 

 

✨  Iterable νŠΉμ§•

잠깐 μ–ΈκΈ‰ν–ˆμ§€λ§Œ iterable 의 κ°€μž₯ 큰 νŠΉμ§•μ€ for..of 문으둜 쑰회, spread 문법, λ°°μ—΄ destructuring λ¬Έλ²•μ˜ λŒ€μƒμ΄ λœλ‹€λŠ” 점이닀. 

 

1. for...of 문 쑰회

 

const arr = [ 1, 2, 3 ];

for (let a of arr) {
    console.log(a)
};

// 1
// 2
// 3

 

for ...of 문은 iterable 을 μ‘°νšŒν•˜λŠ” 것이며, for ...in 문은 객체λ₯Ό μ‘°νšŒν•˜λŠ” ν˜•μ‹μ΄λ‹€. for .. of 문은 iterator 의 next 문을 ν˜ΈμΆœν•˜λ©°, κ·Έ 결과인 iterator result object 의 value λ₯Ό for ...of 문의 λ³€μˆ˜μ— ν• λ‹Ήν•œλ‹€. (μœ„μ˜ κ²½μš°μ—λŠ” a) iterator result object 의 done 값이 true κ°€ λ‚˜μ˜€λŠ” μˆœκ°„, 순회λ₯Ό μ€‘λ‹¨ν•œλ‹€. 

 

β—μœ μ‚¬ λ°°μ—΄ κ°μ²΄λŠ” iterator κ°€ μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— for...of μ‘°νšŒκ°€ λΆˆκ°€λŠ₯ν•˜λ‹€. ν•˜μ§€λ§Œ μ˜ˆμ™Έκ°€ μ‘΄μž¬ν•˜λŠ”λ°, arguments, NodeList , HTMLCollection 은 μœ μ‚¬ λ°°μ—΄ κ°μ²΄μ΄λ©΄μ„œλ„ iterable 이닀. 

 

2. spread 문법

 

console.log(...arr) // 1, 2, 3

 

❗ λ¬Έμžμ—΄μ€ iterable 이기 λ•Œλ¬Έμ— λ°°μ—΄ destructuring 이 κ°€λŠ₯ν•˜μ§€λ§Œ, κ°μ²΄λŠ” μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— λΆˆκ°€λŠ₯ν•˜λ‹€. 

 

let ha = 'haha';
const [b,rest] = ha;
console.log(b) // 'h'

let ha2 = {a:1, b:2};
const [a, b] = ha2; // TypeError

 

3. λ°°μ—΄ destructuring 문법 

 

const [a, ...rest] = arr;
console.log(a) // 1
console.log(rest) // [2, 3]

 

❗ ν—·κ°ˆλ¦¬λ©΄ μ•ˆλ˜λŠ” 것은, iterable 이 μ•„λ‹Œ 객체({})라도 객체 λ¦¬ν„°λŸ΄ λ‚΄μ—μ„œμ˜ spread λ‚˜ destructuring 은 κ°€λŠ₯ν•˜λ‹€.

 

 

✨  Iteration Protocol  의 ν•„μš”μ„±

Iteration Protocol 이 κ·œμ •λ˜κ³  μ—¬λŸ¬ μžλ£Œκ΅¬μ‘°κ°€ iterator 의 ν˜•μ‹μ„ μ·¨ν•˜λ©΄μ„œ, λ‹€μ–‘ν•œ 데이터 κ³΅κΈ‰μž (자료ꡬ쑰) κ°€ ν•˜λ‚˜μ˜ 순회 방식을 갖도둝 κ·œμ •λ˜μ—ˆλ‹€. μ΄λŠ” 데이터 취득과 μ‚¬μš©μ˜ νš¨μœ¨μ„±μ„ ꡉμž₯히 λ†’μ—¬μ£ΌλŠ” 방식이닀. 

 

πŸ“μ‹€μ œ μ‚¬μš©λ‘€

- set λ“±μ˜ μžλ£Œκ΅¬μ‘°μ— μ μš©ν•˜κΈ° 맀우 κ°„νŽΈν•¨ (for.. in λΆˆκ°€λŠ₯) 

- 결과값에 ν•œκ³„λ₯Ό 두지 μ•Šκ³  객체λ₯Ό μ‚¬μš©ν•˜κ³ μž ν•˜λŠ” 경우

- 지연 평가 (lazy evaluation) 이 ν•„μš”ν•œ 경우 : 데이터가 ν•„μš”ν•œ μ‹œμ  μ΄μ „κΉŒμ§€λŠ” 미리 데이터λ₯Ό μƒμ„±ν•˜μ§€ μ•Šλ‹€κ°€ ν•„μš”ν•œ μ‹œμ μ΄ 되면 데이터λ₯Ό μƒμ„±ν•˜λŠ” 기법 

 

 

✨ 참고자료

  • λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive (μœ„ν‚€λΆμŠ€) 

λŒ“κΈ€