본문 바로가기
프로그래밍 개발/JS ES6+

Javascript ES6+ Iterable

by Jinseok Kim 2020. 12. 18.
반응형

 

 

 

 

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

댓글