1. ES5의 리스트 순회
- 일반적인 프로그래밍 언어와 같이 숫자라는 "키"로 순회 하였습니다.
| const list = [1,2,3]; |
| |
| for ( var i = 0; i < list.length; i++ ) { |
| console.log(list[i]); |
| } |
2. ES6의 리스트 순회
- ES6 에서는 가독성을 위해 for of의 사용을 권고합니다.
- 하지만 일반적인 경우와는 달리 "키"가 없는데, 어떤 방식으로 순회를 하는걸까요?
| |
| const ( const val of list ) { |
| console.log(val); |
| } |
3. [ Array, Set, Map ] 을 통해 알아보는 이터러블 & 이터레이터
- 3-1 이터러블 & 이터레이터 이란?
- 자바스크립트의 [ 배열, 객체, 맵 ] 은 이터러블, 이터레이블 프로토콜을 따르는 방식으로 구현이 되어있습니다.
- - 이터러블 ( iterable ) -
- 이터레이터를 관리하는 [Symbol.iterator()] 를 가진 값.
- - 이터레이터 ( iterator )
- - { value, done } 객체를 리턴하는 next()를 가진 값.
- - 이터레블 / 이터레이터 프로토콜
- 이터러블을 for .. of, 전개 연산자 등과 함께 동작 하도록 하는 규약
- 3-2 자바스크립트 배열, 맵, 셋의 작동 방식
- 아래의 예시를 보면 arr는 key로 접근이 가능하지만, set과 Map은 key로 접근이 불가능합니다.
- 즉, 이 사실을 통해 for.. of는 키를 바탕으로 값에 접근 하지 않는다는 것을 알 수 있습니다.
-
| |
| |
| const arr = [1,2,3]; |
| |
| for ( const val of arr ) { |
| console.log(val); |
| } |
| |
| |
| |
| const set = new Set([1,2,3]); |
| |
| console.log(set[1]); |
| |
| for ( const ele of set ) { |
| console.log(ele); |
| } |
| |
| |
| |
| const map = new Map([['a',1], ['b',2], ['c', 3]]); |
| |
| console.log(map[1]); |
| |
| for ( const obj of map ) { |
| console.log(obj); |
| } |
- 작동 방식
- 그렇다면 어떻게 동작하는걸까요?
- arr, map, set은 모두 이터레이블 프로토콜을 기반으로 작동합니다.
- 이터러블 프로토콜은 next를 포함하는 iterator 메소드로 구성이 되어있습니다.
- 그리하여, 값이 있는 경우 done : false & value 가 전달이 되고 없는 경우는 done : true 값이 전달됩니다.
-
| let iterator = arr[Symbol.iterator](); |
| iterator.next() // { value : 1, done : false } |
| iterator.next() // { value : 2, done : false } |
| iterator.next() // { value : 3, done : false } |
| iterator.next() // { value : undefined, done : true } |
-
| const arr1 = [1,2,3]; |
| let iter1 = arr[Symbol.iterator](); |
| iterator.next() // { value : 1, done : false } |
| iterator.next() // { value : 1, done : false } |
| |
| for ( const a of iter1 ) { |
| console.log(a); // 3 |
| } |
4. 사용자 정의 이터러블
- 이터러블에 대한 보다 자세한 이해를 위해 하단의 코드를 작성 해보았습니다.
- 이터레이블 내부에는 총 길이, next(), iterator 를 포함 하고 있습니다.
| const iterable = { |
| [Symbol.iterator]() { |
| |
| let i = 3 |
| |
| return { |
| |
| next() { |
| return i === 0 ? {done : true} : { value : i-- , done : false } |
| }, |
| |
| |
| [Symbol.iterator]() { |
| return this; |
| } |
| } |
| } |
| } |
| |
| let iterator = iterable[Symbol.iterator](); |
| |
| |
| for ( const a of iterator ) { |
| console.log(a); |
| } |
5. 전개 연산자
| const a = [1,2]; |
| |
| console.log([...a, ...[3,4]]); |
| console.log(a); |
6. 제너레이터
- 제너레이터는 이터레이터이자 이터레이터를 생성하는 함수 입니다.
- 제너레이터는 순회할 값을 문장으로 표현하는 것이라고도 말할 수 있습니다.
| function *gen() { |
| yield 1; |
| yield 2; |
| yield 3; |
| |
| return 100; |
| } |
| |
| let iter = gen(); |
| iter[Symbol.iterator](); |
| console.log(iter.next()); // { value : 1, done : false } |
| console.log(iter.next()); // { value : 2, done : false } |
| console.log(iter.next()); // { value : 3, done : false } |
| console.log(iter.next()); // { value : 100, done : ture } |
| |
| for ( const a of gen() ) console.log(a) |
7. 제너레이터 & 이터레이터 ( odds )
- 제너레이터를 다음과 같이 응용하여 사용 할 수 있습니다.
| function *limit(l, iter) { |
| for ( const a of iter ) { |
| yield a; |
| if ( a === l ) { |
| return; |
| } |
| } |
| |
| function *infinity(i = 0) { |
| while ( true ) { |
| yield i++; |
| } |
| } |
| |
| function *odds(ele) { |
| |
| for ( const a of limit( ele, infinity(1)) ) { |
| if ( a % 2 ) { |
| yield i; |
| } |
| |
| |
| } |
| |
| } |
| |
| let iter2 = odds(10); |
| console.log(iter2.next()); |
| console.log(iter2.next()); |
| |
| |
| |
| let iter3 = infinity(); |
| console.log(iter3.next()); |
| console.log(iter3.next()); |
| console.log(iter3.next()); |
| |
| let iter4 = limit(4, [1,2,3,4,5,6]); |
| |
| |
| for ( const a of odds(40) ) console.log(a); |
8. 구조 분해, Spread
| console.log(...odds(10)); |
| console.log(...odds(10), ...odds(20)); |
| |
| const [head, ...tail] = odds(5); |
| console.log(head); |
| console.log(tail); |
| |
| const [a, b, ...rest ] = odds(10); |
| console.log(a); |
| console.log(b); |
| console.log(rest); |