리스트 순회, 이터레이터, 제너레이터

joDMSoluth·2020년 3월 13일
0

함수형프로그래밍

목록 보기
9/17

기존과 달라진 ES6에서의 리스트 순회

기존의 리스트 순회

// 배열
const list = [1, 2, 3];
for(var i = 0; i < list.length; i++) {
  console.log(list[i]);
}

// 유사배열
const str = 'abc';
for(var i = 0; i < str.length; i++) {
  console.log(str[i]);
}

ES6 리스트 순회

// 배열
for(const a of list) {
  console.log(a);
}

// 유사배열
for(const a of str) {
  console.log(a)
}

다양한 리스트 순회

Array를 통해 알아보기

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

Set을 통해 알아보기

const set = new Set([1, 2, 3]);
for(const a of set) console.log(a);

Map을 통해 알아보기

const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
for(const a of map) console.log(a);

Symbol.iterator

  • array의 키로 사용될 수 있다.
const arr = [1, 2, 3];
arr[Symbol.iterator] = null
set[Symbol.iterator] = null
map[Symbol.iterator] = null
for(const a of arr) log(a);
// arr가 iterator가 아니다 라는 에러가 난다.
  • arr, set, map은 자바스크립트의 내장객체로서 이터러블/이터레이터를 따르고 있다.

이터러블/이터레이터 프로토콜

  • 이터러블 : 이터레이터를 리턴하는 Symbol.iterator 를 가진 값
  • 이터레이터 : {value, done} 객체를 리턴하는 next() 를 가진 값
  • 이터러블/이터레이터 프로토콜 : 이터러블을 for...of, 전개 연산자 등과 함께 동작하도록한 규약
const arr = [1, 2, 3];
arr[Symbol.iterator]();
//output : Array iterator {}
let iterator = arr[Symbol.iterator]();
iterator.next();
// output : {value:1, done:false}
iterator.next();
// output : {value:2, done:false}
iterator.next();
// output : {value:3, done:false}
iterator.next();
// output : {value:undefined, done:true}
const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
map.keys()
// output : MapIterator {"a", "b", "c"}
var a = map.keys();
a.next());
// output : {value:"a", done:false}
a.next());
// output : {value:"b", done:false}
a.next());
// output : {value:"c", done:false}
a.next());
// output : {value:undefined, done:true}
var a = map.values()
// output : {value:1, done:false}
var a = map.entries()
// output : {value:["a", 1], done:false}

사용자 정의 이터러블을 통해 알아보기

const iterable = {
  [Symbol.iterator]() {
    let i =3;
    return {
      next() {
        return i===0 ? {done:true} : {value:i--, done:false};
      },
      // welcomed iterator로 만든다.
      [Symbol.iterator]() { return this; } 
    }
  }
};

let iterator = iterable[Symbol.iterator]();
for(const a or iterable) console.log(a);

const arr2 = [1, 2, 3];
let iter2 = arr2[Symbol.iterator]();
iter2.next();
for(const a of iter2) console.log(a);

tip) welcomed iterator : Symbol.iterator 가 자기 자신을 가리키는 이터레이터

예제)

for(const a of document.querySelectorAll('*')) console.log(a);
const all = document.querySelectorAll('*');
let iter3 = all[Symbol.iterator]();
console.log(iter3.next());

전개 연산자

const a = [1, 2];
log([...a, ...arr, ...set, ...map.values()]);

제너레이터/이터레이터

  • 제너레이터 : 이터레이터이자 이터러블을 생성하는 함수
  • 어떠한 값도 순회할 수 있는 형태로 만들 수 있다.
function *gen() {
  yield 1;
  yield 2;
  yield 3;
  if (false) yield 4;
  return 100;
}
let iter = gen();
console.log(iter[Symbol.iterator]() === iter);
// output : true
console.log(iter.next());
// output : {value:1, done:false}
console.log(iter.next());
// output : {value:2, done:false}
console.log(iter.next());
// output : {value:3, done:false}
console.log(iter.next());
// output : {value:100, done:true}

for(const a of gen()) log(a);

odds 제너레이터

function *infinity(i=0) {
  while (true) yield i++;
}

function *limit(l, iter) {
  for(const a of iter) {
    yield a;
    if(a===l) return;
  }
}

function *odds(l) {
  for(const a of limit(l, infinity(1))){
    if(a % 2) yield a;
  }
}
let iter2 = odds(10);
console.log(iter2.next());

for of, 전개 연산자, 구조 분해, 나머지 연산자

console.log(...odds(10)); // 1 3 5 7 9
console.log([...odds(10), ...odds(20)]);
// [1, 3, 5, 7, 9, 1, 3, ...]

const [head, ...tail] = odds(5);
console.log(head); // 1
console.log(tail); // [3, 5]

const [a, b, ...rest] = odds(10);
console.log(a); // 1
console.log(b); // 3
console.log(rest); // [5, 7, 9]
profile
풀스택이 되고 싶은 주니어 웹 개발자입니다.

1개의 댓글

comment-user-thumbnail
2021년 2월 5일

welcomed → well-formed iterable이 맞습니다.

답글 달기