Iterable
Iterable의 정의
- 내부 요소들을 공개적으로 탐색(반복)할 수 있는 데이터 구조.
- [Symbol.iterator] 메소드를 가지고 있다.
아래와 같은 코드들이 iterable한 예이다.
const arr = ['a', 'b', 'c']
const set = new Set(['a', 'b', 'c'])
const map = new Map([[false, 'no'], [true, 'yes'], ['well', 'soso']])
const str = '문자열도 이터러블하다'
※ Iterable의 의미는 내부 요소들을 공개적으로 반복 및 탐색할 수 있는 데이터 요소를 뜻한다. [Symbol.Iterable] 매소드를 가지고 있는 것이 특징이다.
개체 자신이 iterable한 경우
- array, map, set, string 등이 존재한다.
- `[Symbol.iterator]` 메소드가 존재하는 모든 개체이다.
console.dir([1, 2, 3])
console.dir(new Set([1, 2, 3]))
console.dir(new Map([[0, 1], [1, 2], [2, 3]]))
//결과:
//Array(3)
//Set(3)
//Map(3)
아래 코드는 `[Symbol.iterator]` 메소드가 존재하지 않고 단지 유사배열객체이다.
const obj = { 0: 1, 1: 2, 2: 3, length: 3 }
console.dir(obj)
//결과:
//0: 1
//1: 2
//2: 3
//length: 3
`generator`를 호출한 결과 또한 iterable한 개체로 볼 수 있다.
function* generator () { //함수 뒤에 * 표시가 generator의 특징이다.
yield 1
yield 2
yield 3
}
const gene = generator()
gene.next() //.next로 호출해주면 literable하게 객체가 나온다.
//{value: 1, done: false}
gene.next()
//{value: 2, done: false}
gene.next()
//{value: 3, done: false}
gene.next()
//{value: undefined, done: true} //더 이상 나올 것이 없자 정의되지 않는다.
iterable한 개체의 특징
모두 내부적으로는 `Symbol.iterator` 또는 `generator`을 실행하여 iterator로 변환한 상태에서 `next()`를 반복 호출하는 동일한 로직을 기반으로 함.
1) Array.from 메소드로 Iterable한 개체를 배열로 전환 가능
※ Array.from이라는 메소드의 인자에 Iterable한 개체가 들어가면 배열로 바꿔준다.원래 배열이었든 배열이 아니지만Iterable한 개체이든 모두 배열로 전환시킨다.
const arr = [1, 2, 3]
const map = new Map([['a', 1], ['b', 2], ['c', 3]])
const set = new Set([1, 2, 3])
const str = '이런것도 된다.'
const gene = (function* () {
yield 1
yield 2
yield 3
})()
const arrFromArr1 = Array.from(arr) // [1, 2, 3] (원래 배열이어서 배열로 다시 나옴)
const arrFromMap1 = Array.from(map) // [Array(2), Array(2), Array(2)]
const arrFromSet1 = Array.from(set) // [1, 2, 3]
const arrFromStr1 = Array.from(str) // ["이", "런", "것", "도", " ", "된", "다", "."]
const arrFromGene1 = Array.from(gene) // [1, 2, 3]
2) spread operator로 Iterable한 개체를 배열로 전환 가능
const arr = [1, 2, 3]
const map = new Map([['a', 1], ['b', 2], ['c', 3]])
const set = new Set([1, 2, 3])
const str = '이런것도 된다.'
const gene = (function* () {
yield 1
yield 2
yield 3
})()
const arrFromArr2 = [...arr] // [1, 2, 3]
const arrFromMap2 = [...map] // [Array(2), Array(2), Array(2)]
const arrFromSet2 = [...set] // [1, 2, 3]
const arrFromStr2 = [...str] // ["이", "런", "것", "도", " ", "된", "다", "."]
const arrFromGene2 = [...gene] // [1, 2, 3]
3) Iterable한 개체는 해체할당 가능
const arr = [1, 2, 3]
const map = new Map([['a', 1], ['b', 2], ['c', 3]])
const set = new Set([1, 2, 3])
const str = '이런것도 된다.'
const gene = (function* () {
yield 1
yield 2
yield 3
})()
const [arrA, , arrC] = arr
const [mapA, , mapC] = map
const [ , setB, setC] = set
const [ , strB, ...strRest] = str
const [geneA, ...geneRest] = gene
console.log(arrA, arrC) // 1 3
console.log(mapA, mapC) // ["a", 1] ["c", 3]
console.log(setB, setC) // 2 3
console.log(strB, strRest) // 런 ["것", "도", " ", "된", "다", "."]
console.log(geneA, geneRest) // 1 [2, 3]
4) Iterable한 개체로 for ... of 명령 수행 가능
const arr = [1, 2, 3]
const map = new Map([['a', 1], ['b', 2], ['c', 3]])
const set = new Set([1, 2, 3])
const str = '이런것도 된다.'
const gene = (function* () {
yield 1
yield 2
yield 3
})()
for (const x of arr) {
console.log(x)
}
//1
//2
//3
for (const x of map) {
console.log(x)
}
//["a", 1]
//["b", 2]
//["c", 3]
for (const x of set) {
console.log(x)
}
//1
//2
//3
for (const x of str) {
console.log(x)
}
//이
//런
//것
//도
//
//된
//다
//.
for (const x of gene) {
console.log(x)
}
//1
//2
//3
5) `Promise.all`, `Promise.race` 명령 수행 가능
const a = [
new Promise((resolve, reject) => { setTimeout(resolve, 500, 1) }),
new Promise((resolve, reject) => { setTimeout(resolve, 100, 2) }),
3456,
'abc',
new Promise((resolve, reject) => { setTimeout(resolve, 300, 3) }),
]
Promise.all(a) // 인자로 들어간 변수 a와 같은 iterable한 것이 들어 올 수 있다.
.then(v => { console.log(v) })
.catch(err => { console.error(err) })
const s = new Set([
new Promise((resolve, reject) => { setTimeout(resolve, 300, 1) }),
new Promise((resolve, reject) => { setTimeout(resolve, 100, 2) }),
new Promise((resolve, reject) => { setTimeout(reject, 200, 3) }),
])
Promise.race(s)
.then(v => { console.log(v) })
.catch(err => { console.error(err) })
//결과:
//2
//[1, 2, 3456, "abc", 3] (
6) `generator - yield*` 문법으로 이용 가능
const arr = [1, 2, 3]
const map = new Map([['a', 1], ['b', 2], ['c', 3]])
const set = new Set([1, 2, 3])
const str = '이런것도 된다.'
const makeGenerator = iterable => function* () {
yield* iterable
//만약 iterable의 매개변수로 변수 arr를 받느다면
//yield 1;
//yield 2;
//yield 3; 과 같은 의미이다.
}
const arrGen = makeGeneratoryield 3;(arr)()
const mapGen = makeGenerator(map)()
const setGen = makeGenerator(set)()
const strGen = makeGenerator(str)()
console.log(arrGen.next()) // {value: 1, done: false}
console.log(mapGen.next()) // {value: Array(2), done: false}
console.log(...setGen) // 1 2 3
console.log(...strGen) // 이 런 것 도 된 다 .
7) iterable 객체에 `[Symbol.iterator]`가 잘 정의되지 않은 경우
const obj = {
a: 1,
b: 2,
[Symbol.iterator] () {
return 1
}
}
console.log([...obj])
//결과: 오류
객체 내에 Symbol.ilterator가 정의되어 들어간다 해도 홀로 있으면 다른 조건이 필요해 iterable한 개체가 되지 않고 성립되지 않는다. 그 조건이란 ilterator를 return으로 반환하는 조건이다.
iterable한 개체를 인자로 받을 수 있는 개체
new Map()
new Set()
new WeakMap()
new WeakSet()
Promise.all()
Promise.race()
Array.from()
'프로그래밍 개발 > JS ES6+' 카테고리의 다른 글
Javascript ES6+ Generator (0) | 2020.12.18 |
---|---|
Javascript ES6+ Iterator (0) | 2020.12.18 |
Javascript ES6+ Map (0) | 2020.12.16 |
Javascript ES6+ Set (0) | 2020.12.16 |
Javascript ES6+ 심볼(Symbol) (0) | 2020.12.15 |
댓글