[JS] ๐ ์ดํฐ๋ฌ๋ธ & ์ดํฐ๋ ์ดํฐ - ๐ฏ์๋ฒฝ ์ดํด
์ดํฐ๋ฌ๋ธ(interable)
์ดํฐ๋ฌ๋ธ(interable)์ด๋ ์๋ฃ๋ฅผ ๋ฐ๋ณตํ ์ ์๋ ๊ฐ์ฒด๋ฅผ ๋งํ๋ ๊ฒ์ด๋ค.
์ฐ๋ฆฌ๊ฐ ํํ ์ฐ๋ ๋ฐฐ์ด ์ญ์ ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด์ด๋ค.
๊ทธ๋ผ ๋ง์ผ ์ด ๋ฐฐ์ด์๊ฒ ์ดํฐ๋ฌ๋ธ ํ์์ ์์ ๋ฒ๋ฆฌ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
let arr = [1,2,3]
for(const a of arr) console.log (a) // ์ ์์๋ 1,2,3
arr[Symbol.iterator] = null; // ์ด๋ ๊ฒ ํ๋ฉด ์ํ๊ฐ ๋์ง ์๋๋ค
for(const a of arr) console.log (a) // Uncaught TypeError: arr is not iterable
๋ฉ์ฉกํ ๋ฐฐ์ด์์ ๋ถ๊ตฌํ๊ณ for..of๋ก ์ํํ ์๊ฐ ์๊ฒ ๋์๋ค.
์ [Symbol.iterator] ๋ผ๋ ์ฝ๋๊ฐ ๋์ ๋๋ค. ์ด์ ์ ๊ฒ์ด ๋ฌด์์ธ์ง ์์๋ณด์.
์ดํฐ๋ฌ๋ธ๊ณผ ์ดํฐ๋ ์ดํฐ
iterable Prococal / iterator Prococal
์ ์ : ์ดํฐ๋ฌ๋ธ์ [for...of], [์ ๊ฐ ์ฐ์ฐ์], [๋น๊ตฌ์กฐํ] ..๋ฑ, ์ดํฐ๋ฌ๋ธ์ด๋ ์ดํฐ๋ ์ดํฐ ํ๋กํ ์ฝ์ ๋ฐ๋ฅด๋ ์ฐ์ฐ์๋ค๊ณผ ํจ๊ป ๋์ํ๋๋ก ํ๋ ์ฝ์๋ ๊ท์ฝ์ ์๋ฏธํ๋ค.
๊ทธ๋์ ์ดํฐ๋ฌ๋ธ์ด๋ ์ดํฐ๋ฌ๋ธ ๊ท์ฝ์ ๋ฐ๋ฅด๋ ๊ฐ์ฒด์ธ ์ ์ด๋ค.
โ
iterable
์ ์ : ์ดํฐ๋ ์ดํฐ๋ฅผ ๋ฆฌํดํ๋ [Symbol.iterator]() ๋ฉ์๋๋ฅผ ๊ฐ์ง ๊ฐ์ฒด
๋ฐฐ์ด์ ๊ฒฝ์ฐ Array.prototype ์ Symbol.iterator ๋ฅผ ์์๋ฐ๊ธฐ ๋๋ฌธ์ ์ดํฐ๋ฌ๋ธ์ด๋ค. ๋ฌธ์์ด๋ ๋ง์ฐฌ๊ฐ์ง
โ
iterator
์ ์ : {value : ๊ฐ , done : true/false} ํํ์ ์ดํฐ๋ ์ดํฐ ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๋ next() ๋ฉ์๋๋ฅผ ๊ฐ์ง ๊ฐ์ฒด.
next ๋ฉ์๋๋ก ์ํ ํ ์ ์๋ ๊ฐ์ฒด๋ค.
[Symbol.iterator]() ์์ ์ ์ ๋์ด์๋ค.
const arr = [1,2,3]; //arr๋ ๊ทธ๋ฅ ํ๋ฒํ ๋ฐฐ์ด
const iter = arr[Symbol.iterator]();
/*
๋ฌธ๋ฒ ํํค์น๊ธฐ : key๊ฐ์ ๋ฌธ์์ด์ด ์๋ ๋ณ์๋ก ์ฃผ๊ธฐ์ํด arr[๋ณ์] ํํ๋ฅผ ๊ฐ์ง๋ค.
์ ์ฌ์ง์์ ๋ณด๋ฏ์ด, Symbol.iterator ๋ผ๋ key๊ฐ์ ๊ฐ์ง๊ณ value๋ ํจ์์ด๋ค.
์ด๋ฅผ ์ ๊ทผํด์ ํจ์์คํ() ์ํค๋ฉด ์ดํฐ๋ ์ดํฐ ๊ฐ์ฒด๊ฐ ๋ฐํ๋์ด iter์ ๋ด๊ธฐ๊ฒ ๋๋ค.
*/
iter.next()
//>{value:1,done: false}
iter.next()
//>{value:2, done: false},
iter.next()
//{value:3, done: false}
iter.next()
//{value: undefined, done: true}
[Symbol.iterator]
์ฌ์ ํ ์ดํฐ๋ฌ๋ธ / ์ดํฐ๋ ์ดํฐ ๊ฐ๋ ์ด ๋ญ ์๋ฆฌ์ธ์ง ๋ชจ๋ฅด๊ฒ์ด๋ค.
์ง์ ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ์ดํฐ๋ฌ๋ธ์ด๋ผ๋ ๊ฐ๋ ์ ์ดํดํด ๋ณด๋๋ก ํ์.
let range = { // 1) ๊ฐ์ฒด ์์ฑ
from: 1,
to: 5
};
range[Symbol.iterator] = function() { // 2) ์๋ก์ด ํค:๋ฐธ๋ฅ ๋ฅผ ์ถ๊ฐํ๋ค. ํค๋ ๋ณ์ํํ, ๋ฐธ๋ฅ๋ ํจ์์ด๋ค.
return { // ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๋ค. ๊ทธ๋ฐ๋ฐ ์ข ํน๋ฒฝํ ํํ์ ๊ฐ์ฒด
current: this.from,
last: this.to,
next() { // 3) next() ์ ์
if (this.current <= this.last) {
return { done: false, value: this.current++ };
// 4) {value : ๊ฐ , done : true/false} ํํ์ ์ดํฐ๋ ์ดํฐ ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํฉ๋๋ค.
} else {
return { done: true };
}
}
};
};
ํ๋ฒํ range๊ฐ์ฒด๋ฅผ ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋ก ๋ง๋๋ ๊ณผ์ ์ ๋ด ์๋ค.
- ํ๋ฒํ range๊ฐ์ฒด๋ฅผ ๋ง๋ ๋ค.
- ์ฐ๋ฆฌ๊ฐ ํํ์ฐ๋ ๊ฐ์ฒด์ ์๋ก์ด key:value๋ฅผ ์ถ๊ฐํ๊ณ ์ถ์๋, range[key] = value ๋ฅผ ํตํด Symbol.iterator ํค๊ฐ๊ณผ ๋ฐธ๋ฅ๋ ํจ์๋ฅผ ์ง์ ํด ๋ฃ์๋ค.
- ์ถ๊ฐํ ํจ์๋ ์ด๋ ํ ํน๋ณํ ๊ฐ์ฒด๋ฅผ returnํ๊ฒ ๋์ด์๊ณ , ์ด ๊ฐ์ฒด ์์ next()๋ผ๋ ๋ฉ์๋๋ฅผ ์ ์ ํ์๋ค.
- ์ต์ข ์ ์ผ๋ก {value : ๊ฐ , done : true/false} ํํ์ ์ดํฐ๋ ์ดํฐ ๊ฐ์ฒด๋ฅผ returnํ๋ค.
โ
Q. ์, ๊ทธ๋ผ ์ด์ ๋ฌด์์ด ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด์ด๊ณ , ๋ฌด์์ด ์ดํฐ๋ ์ดํฐ ์ผ๊น?
- ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋ range๋ค. ์๋ํ๋ฉด Symbol.iterator๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ
- ์ดํฐ๋ ์ดํฐ ๊ฐ์ฒด๋ Symbol.iterator() ๋ฉ์๋์์ ๋ฆฌํดํ ๊ฐ์ฒด๊ฐ ๋ฐ๋ก ์ดํฐ๋ ์ดํฐ๋ค. ์๋ํ๋ฉด ์ด ๊ฐ์ฒด ์์๋ {value : ๊ฐ , done : true/false}๋ฅผ ๋ฆฌํดํ๋ next()๋ฉ์๋๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค.
โ
์ด๋ฒ์๋ ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๊ฐ for..of์์ ์ด๋ป๊ฒ ์ํํ๋์ง ๊ณผ์ ์ ์์๋ณด์.
let range = { // ๊ฐ์ฒด ์์ฑ
from: 1,
to: 5
};
// 1. for..of ์ต์ด ํธ์ถ ์, Symbol.iterator๊ฐ ํธ์ถ๋ฉ๋๋ค.
range[Symbol.iterator] = function() {
// Symbol.iterator๋ ์ดํฐ๋ ์ดํฐ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
// 2. ์ดํ for..of๋ ๋ฐํ๋ ์ดํฐ๋ ์ดํฐ ๊ฐ์ฒด๋ง์ ๋์์ผ๋ก ๋์ํ๋๋ฐ, ์ด๋ ๋ค์ ๊ฐ๋ ์ ํด์ง๋๋ค.
return {
current: this.from,
last: this.to,
// 3. for..of ๋ฐ๋ณต๋ฌธ์ ์ํด ๋ฐ๋ณต๋ง๋ค next()๊ฐ ํธ์ถ๋ฉ๋๋ค.
next() {
// 4. next()๋ ๊ฐ์ ๊ฐ์ฒด {done:.., value :...}ํํ๋ก ๋ฐํํด์ผ ํฉ๋๋ค.
if (this.current <= this.last) {
return { done: false, value: this.current++ }; // ์ํ ์งํ
} else {
return { done: true }; // ์ํ ์ข
๋ฃ
}
}
};
};
// ์ด์ ์๋ํ ๋๋ก ๋์ํฉ๋๋ค!
for (let num of range) {
alert(num); // 1, 2, 3, 4, 5
}
- for..of๊ฐ ์์๋์๋ง์ for..of๋ Symbol.iterator๋ฅผ ํธ์ถํ๋ค.
- ์ดํ for..of๋ ๋ฐํ๋ ๊ฐ์ฒด(์ดํฐ๋ ์ดํฐ)๋ง์ ๋์์ผ๋ก ๋์ํ๋ค.
- for..of์ ๋ค์ ๊ฐ์ด ํ์ํ๋ฉด, for..of๋ ์ดํฐ๋ ์ดํฐ์ next()๋ฉ์๋๋ฅผ ํธ์ถํ๋ค.
- next()์ ๋ฐํ ๊ฐ์ {done: Boolean, value: any}์ ๊ฐ์ ํํ์ด์ด์ผ ํ๋ค. ๊ทธ๋์ผ ์ํ๊ฐ ๋๋ค.
done=true๋ ๋ฐ๋ณต์ด ์ข ๋ฃ๋์์์ ์๋ฏธํ๋ค. done=false์ผ๋ value์ ๋ค์ ๊ฐ์ด ์ ์ฅ๋๋ค.
โ
* ํ๋ฐฉ์ ์ดํฐ๋ฌ๋ธ+์ดํฐ๋ ์ดํฐ ๊ตฌํํ๊ธฐ
ํ ๊ฐ์ฒด์ ์์ ์ดํฐ๋ ์ดํฐ ํ์์ ์ ์ํดํ๋ฉด, range๊ฐ์ฒด๋ ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด์ด์ ์ดํฐ๋ ์ดํฐ ๊ฐ์ฒด ์ญํ ์ ๋ชจ๋ ์ํํ ์ ์๋ค. ํํ๋ง ๋ค๋ฅผ๋ถ ์คํ์์ฒด๋ ์์ ์ฐจ์ด์๋ค.
let range = {
from: 1,
to: 5,
[Symbol.iterator]() { // ์์ฑ์
this.current = this.from;
this.last = this.to;
return this; // ์๊ธฐ ์์ ์ ๋ฐํ. ์๊ธฐ์์ ์ next()๋ฉ์๋๊ฐ ์ ์๋์ด์์ผ๋, next()๋ฉ์๋
// ์์์ this๋ ์์ฑ์๋ก ์์ฑ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๊ฒ ๋๋ค.
},
next() { // ์์ ๊ฐ์ฒด์์ next()๋ฉ์๋๋ฅผ ์ ์.
if (this.current <= this.to) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
for (let num of range) {
alert(num); // 1, 2, 3, 4, 5
}
์ ์ฌ๋ฐฐ์ด vs ์ดํฐ๋ฌ๋ธ
- โ์ดํฐ๋ฌ๋ธ(iterable) : ์์์ ์ค๋ช ํ ๋ฐ์ ๊ฐ์ด ๋ฉ์๋ Symbol.iterator๊ฐ ๊ตฌํ๋ ๊ฐ์ฒด.
- ์ ์ฌ ๋ฐฐ์ด(array-like) : ์ธ๋ฑ์ค์ length ํ๋กํผํฐ๊ฐ ์์ด์ ๋ฐฐ์ด์ฒ๋ผ ๋ณด์ด๋ ๊ฐ์ฒด.
* Map์๋ฃํ์ด๋ DOM์์ ๋ฐํํ๋ ๋ฐฐ์ด, arguments๋ฐฐ์ด์ ๋ชจ๋ ์ดํฐ๋ฌ๋ธ ์์ ์ด ๋ง์ณ์ง ์ ์ฌ๋ฐฐ์ด์ด๋ค.
์๋ ์ ์ ์ฌ๋ฐฐ์ด์ ์ํ๊ฐ ๋ถ๊ฐ๋ฅํ๋ค.
โ์๋ ์์์ ๊ฐ์ฒด๋ ์ ์ฌ ๋ฐฐ์ด ๊ฐ์ฒด์ด๊ธด ํ์ง๋ง ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๊ฐ ์๋๋ค.
let arrayLike = { // ์ธ๋ฑ์ค์ lengthํ๋กํผํฐ๊ฐ ์์ => ์ ์ฌ ๋ฐฐ์ด
0: "Hello",
1: "World",
length: 2
};
for (let item of arrayLike) {} // Symbol.iterator๊ฐ ์์ผ๋ฏ๋ก ์๋ฌ ๋ฐ์
์ดํฐ๋ฌ๋ธ๊ณผ ์ ์ฌ ๋ฐฐ์ด์ ๋ฐฐ์ด์ด ์๋๊ธฐ ๋๋ฌธ์ push, pop ๋ฑ์ ๋ฉ์๋๋ฅผ ์ง์ํ์ง ์๋๋ค.
์ดํฐ๋ฌ๋ธ๊ณผ ์ ์ฌ ๋ฐฐ์ด์ ๋ฐฐ์ด์ฒ๋ผ ๋ค๋ฃจ๊ณ ์ถ์ ๋ ์ด๋ฐ ํน์ง์ ๋ถํธํจ์ ์ด๋ํ๊ฒ ๋๋ค.
์๋ฅผ๋ค์ด, range์ ๋ฐฐ์ด ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ๋ฌด์ธ๊ฐ๋ฅผ ํ๊ณ ์ถ์ ๋์ฒ๋ผ ๋ง์ด๋ค.
์ด๋ป๊ฒ ํ๋ฉด ์ดํฐ๋ฌ๋ธ๊ณผ ์ ์ฌ ๋ฐฐ์ด์ ๋ฐฐ์ด ๋ฉ์๋๋ฅผ ์ ์ฉํ ์ ์์๊น? ์ ๋ต์ ์ ์ฌ๋ฐฐ์ด์ ์ง์ง๋ฐฐ๊ธฐ ๋ฐฐ์ด๋ก ๋ณํํด์ฃผ๋ฉด ๋๋ค.
โ
> Array.from ๋ฉ์๋
๋ฒ์ฉ ๋ฉ์๋ Array.from๋ ์ดํฐ๋ฌ๋ธ์ด๋ ์ ์ฌ ๋ฐฐ์ด์ ๋ฐ์ ‘์ง์ง’ Array๋ฅผ ๋ง๋ค์ด์ค๋ค.
์ด ๊ณผ์ ์ ๊ฑฐ์น๋ฉด ์ดํฐ๋ฌ๋ธ์ด๋ ์ ์ฌ ๋ฐฐ์ด์ ๋ฐฐ์ด ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
let arrayLike = { //์ ์ฌ๋ฐฐ์ด
0: "Hello",
1: "World",
length: 2
};
Array.from(arrayLike); // ["Hello", "World"]
let arr = Array.from(arrayLike); // ["Hello", "World"] ๋ฐฐ์ด์ด ๋จ์ผ๋ก์ ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋ ๋๋ค.
for (let item of arr) {} // 1,2,3,4,5 (๋ฐฐ์ด-๋ฌธ์์ด ํ ๋ณํ์ด ์ ๋๋ก ๋์ํฉ๋๋ค.)
๋ฌธ์์ด๋ ์ดํฐ๋ฌ๋ธ
๋ฐฐ์ด๊ณผ ๋ฌธ์์ด์ ๊ฐ์ฅ ๊ด๋ฒ์ํ๊ฒ ์ฐ์ด๋ ๋ด์ฅ ์ดํฐ๋ฌ๋ธ์ด๋ค.
for (let char of "test") {
// ๊ธ์ ํ๋๋น ํ ๋ฒ ์คํ๋ฉ๋๋ค(4ํ ํธ์ถ).
alert( char ); // t, e, s, t๊ฐ ์ฐจ๋ก๋๋ก ์ถ๋ ฅ๋จ
}
โ
Map๊ณผ Set ์๋ฃํ๋ ์ดํฐ๋ฌ๋ธ
๋งต๊ณผ ์ ์ ์๋ฐํ ๋ ๋ฆฌ๋ ์๋ฃํ์ด์ง ๊ฐ์ฒด๋ ๋ฐฐ์ด์ด ์๋๋ค.
๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ for..of๋ฌธ๊ณผ ๋์ํ๋ ์ด์ ๋ ์ธ๋ฑ์ค๋ก ์ ๊ทผํ๋๊ฒ ์๋ ์ดํฐ๋ฌ๋ธ ํ๋กํ ์ฝ์ ๋ฐ๋ฅด๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๋ํ ์์ฒด์ ์ผ๋ก ์์ฒด ๋ด์ฅ forEach()๋ฉ์๋๋ฅผ ์ง์ํ๊ธฐ๋ ํ๋ค.
const set = new Set([1,2,3])
for (cosnt a of set) console.log(a) // 1,2,3
const map = new Map([['a',1],['b',2],['c',3]]);
// Map(3) {"a" => 1, "b" => 2, "c" => 3}
const iter = map[Symbol.itertator](); // ์ฌ๋ณผ.์ดํฐ๋ ์ดํฐ๊ฐ ์์ฒด ๋ด์ฅ๋์๊ธฐ์ ๋ถ๋ฌ์ค๊ธฐ๋ง ํ๋ฉด
iter.next();
// {value: Array(2), done: false}
for(const a of map)
console.log(a); // ['a',1],['b',2],['c',3]
์์)
: Map์๋ฃํ ๊ฐ์๊ธ์์ ์์ธํ ๋ค๋ฃฌ๋ค.
map.keys()
- value์ key ๋ง ์๋ ์ดํฐ๋ ์ดํฐ๋ฅผ ๋ฐํ. (์ํ ๊ฐ๋ฅ)
map.values()
- values์ map์ valuse๋ง ์๋ ์ดํฐ๋ ์ดํฐ ๋ฐํ
map.entries()
- key ์ value๊ฐ ์๋ ์ดํฐ๋ ์ดํฐ๋ฅผ ๋ฐํ
map.keys() // MapIterator {"a", "b", "c"}
Reference
https://ko.javascript.info/iterable
https://pks2974.medium.com/javascript%EC%99%80-iterator-cdee90b11c0f
โ