(JS) Iterable

Mirrer·2022년 5월 1일
0

JavaScript

목록 보기
11/24
post-thumbnail

이터러블 (Iterable)

이터러블은 요소를 하나씩 차례로 반환 가능한 object

ES6에서 자바스크립트에 두 가지 새로운 개념인 iterableiterator를 도입했다.

Iterable 하다는건, 순회가 가능하다는 것이다 또한 순회가 가능하면 관련된 반복문, 연산자들을 사용할 수 있다.

Iterable이란 일반적으로 데이터를 소비할 수 있는 데이터 구조이다. 주로 반복자를 반환하는 Symbol.iteratorkeymethod를 구현하여 수행한다.


Iterable의 필요성

Javascript의 데이터 소스가 있는 경우 데이터를 구조화하는 방법에 따라 다른 방식으로 소비해야 한다.

Array의 데이터를 반복하고 소비하는 것은 { key, value } 객체와 다르다.

새로운 데이터 소스를 각각 다른 방법으로 소비하는 것은 실용적이지 않다.

즉 모든 데이터 소스가 동일한 방식으로 소비될 수 있는 인터페이스가 필요하다.

Symbol.iterator

IterableSymbol.iterator메서드가 구현되어 있어야 한다.

구현한 [Symbol.iterator]메서드의 결과는 iterator라고 부른다. 이 iterator는 이어지는 반복 과정을 처리한다.

iterator객체에는 { done: Boolean, value: any }를 반환하는 메서드 next()반드시 구현되어야 한다.

iterator객체의 done속성은 반복의 종료 유무를 의미하고, value속성은 다음 값을 나타낸다.

IterableIterator객체를 반환하는 메서드

  • values()

  • entries()

  • keys()

const arr = [1, 2, 3];
console.log(arr.values()); // Object [Array Iterator] {}
console.log(arr.entries()); // Object [Array Iterator] {}
console.log(arr.keys()); // Object [Array Iterator] {}

Iterator 사용

  • IterableIterator객체를 활용하여 메서드 사용
const array = [1, 2, 3];

for (let item of array.values()) {
  console.log(item); // 1 2 3 
}

// array자체가 iterable하기 때문에 메서드 생략가능
for (let item of array) {
  console.log(item); // 1 2 3 
}
  • 직접적으로 메서드 사용
const array = [1, 2, 3];

const iterator = array.values();
while(true) {
  const item = iterator.next();
  if (item.done) break;
  console.log(item.value); // 1 2 3
}

일반 객체는 iterable하지 않다.

  • 일반 객체는 iterator함수가 없기 때문에 of연산자를 사용할 수 없다.
const obj = { id: 123, name: 'mirrer' };

for (const item of obj) {
  console.log(item); // TypeError: obj is not iterable
}
  • 객체를 순회하면서 key를 가져오는 in연산자는 사용 가능하다.
const obj = { id: 123, name: 'mirrer' };

for (const key in obj) {
  console.log(key); // id name
}

제너레이터 (Generator)

Iterator를 간편하게 만드는 방법

일반 함수는 하나의 값만을 반환합니다.

하지만 generator를 사용하면 여러 개의 값을 필요에 따라 하나씩 yield(반환)할 수 있다.

제너레이터와 이터러블 객체를 함께 사용하면 손쉽게 데이터 스트림을 만들 수 있다.


제너레이터 사용

제너레이터를 만들기 위해서는 제너레이터 함수라 불리는 특별한 문법 구조, function*이 필요하다.

function* generateSequence() {
  yield 1;
  yield 2;
  return 3;
}

제너레이터 함수는 일반 함수와 동작 방식이 다르다.

제너레이터 함수는 호출하면 코드가 실행되지 않고, 대신 실행을 처리하는 특별 객체, '제너레이터 객체’가 반환된다.

function* generateSequence() {
  yield 1;
  yield 2;
  return 3;
}


// '제너레이터 함수'는 '제너레이터 객체'를 생성
let generator = generateSequence();
console.log(generator); // [object Generator]

제너레이터의 주요 메서드 next()는 호출하면 가장 가까운 yield <value>문을 만날 때까지 실행이 지속된다.

yield <value>문을 만나면 실행이 멈추고 산출하고자 하는 값인 value바깥 코드에 반환된다.

next()는 항상 value, done 두 프로퍼티를 가진 객체를 반환한다.

function* multipleGenerator() {
  for (let i = 0; i < 10; i++) {
    console.log(i);
    yield i ** 2; // 다음 사용자가 next를 호출할때까지 대기
  }
}

const multiple = multipleGenerator();
let next = multiple.next(); // 0
next = multiple.next(); // 1
next = multiple.next(); // 2
  • Generator return : 제너레이터를 종료
// generator사용
function* multipleGenerator() {
  for (let i = 0; i < 10; i++) {
    console.log(i);
    yield i ** 2; // 다음 사용자가 next를 호출할때까지 대기
  }
}

const multiple = multipleGenerator();
let next = multiple.next(); // 0
multiple.return(); // 제너레이터의 반복을 종료

next = multiple.next(); // 출력 X
next = multiple.next(); // 출력 X
  • Generator throw : 제너레이터의 에러실행
// generator사용
function* multipleGenerator() {
  for (let i = 0; i < 10; i++) {
    console.log(i);
    yield i ** 2; // 다음 사용자가 next를 호출할때까지 대기
  }
}

const multiple = multipleGenerator();
let next = multiple.next(); // 0
multiple.throw('Error!!'); // 제너레이터의 에러실행

next = multiple.next(); // 출력 X
next = multiple.next(); // 출력 X

발생한 에러는 try ~ catch문으로 해결

// generator사용
function* multipleGenerator() {
  try {
    for (let i = 0; i < 10; i++) {
      console.log(i);
      yield i ** 2; // 다음 사용자가 next를 호출할때까지 대기
    }
  } catch (error) {
    console.log(error);
  }
}

const multiple = multipleGenerator();
let next = multiple.next(); // 0
multiple.throw('Error!!'); // 제너레이터의 에러실행

next = multiple.next(); // 출력 X
next = multiple.next(); // 출력 X

스프레드(Spread) 연산자

배열, 문자열, 객체 등 반복 가능한 객체 (Iterable Object)를 개별 요소로 분리

ECMAcmaScript 2018에 추가된 스프레드 연산자는 순회가 가능한 모든 것들은 펼칠 수 있다.

즉 모든 IterableSpread가될 수 있다. (func(...iterable), [...iterable], { ...obj })

function add(a, b, c) {
  return a + b + c;
}

const nums = [1, 2, 3];
// console.log(add(nums[0], nums[1], nums[2])); -> X
console.log(add(...nums)); // 6

  • Rest Parameters
function sum(first, second, ...nums) {
  console.log(nums);
}

sum(1, 2, 3, 4, 5, 6); // 3 4 5 6
  • Array Concat
const fruits1 = ['apple', 'peach'];
const fruits2 = ['banana', 'watermelon'];

let arr = fruits1.concat(fruits2);
console.log(arr); // [ 'apple', 'peach', 'banana', 'strawberry' ]

arr = [...fruits1, ...fruits2];
console.log(arr); // [ 'apple', 'peach', 'banana', 'strawberry' ]

arr = [...fruits1, 'grape' , ...fruits2];
console.log(arr); // [ 'apple', 'peach', 'grape', 'banana', 'strawberry' ]
  • Object
const mirrer = { name: 'mirrer', age: 30 };
const updated = {
  ...mirrer,
  job: 'web developer',
}

// 새로운 오브젝트를 생성해서 기존의 객체에는 변화 X
console.log(mirrer); // { name: 'mirrer', age: 30 }
console.log(updated); // { name: 'mirrer', age: 30, job: 'web developer' }

구조 분해 할당 (Desturcturing Assignment)

데이터를 그룹화하여 쉽게 만들 수 있는 표현식

구조 분해 할당 구문은 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식이다.

구조 분해 할당을 사용하면 배열안에서도 의미 있는 변수명을 전달할 수 있다.


  • 예제 1
const fruits = ['apple', 'banana', 'watermelon', 'peach', 'orange'];
const [first, second, ...others] = fruits;

console.log(first); // apple
console.log(second); // banana
console.log(others); // [ 'watermelon', 'peach', 'orange' ]
  • 예제 2
const point = [1, 2];
const [x, y, z = 9] = point;

console.log(x); // 1
console.log(y); // 2
console.log(z); // 9
  • 예제 3
function createFruits() {
  return ['apple', 'banana'];
}

const [fruit1, fruit2] = createFruits();
console.log(fruit1); // apple
console.log(fruit2); // banana
  • 예제 4
const mirrer = { name: 'mirrer', age: 30, job: 'web developer' };
function display({ name, age, job }) {
  console.log(name);
  console.log(age);
  console.log(job);
}

display(mirrer); // mirrer 30 web developer
  • 예제 5
const mirrer = { name: 'mirrer', age: 30, job: 'web developer' };
const { name, age, job: occupation, pet = '강아지' } = mirrer;

console.log(name); // mirrer
console.log(age); // 30
console.log(occupation); // web developer
console.log(pet); // 강아지

참고 자료

Iteration protocols - JavaScript | MDN
Generator - JavaScript - MDN Web Docs
Spread operator - JavaScript | MDN - LIA
구조 분해 할당 - JavaScript | MDN
모던 자바스크립트 Deep Dive
모던 JavaScript 튜토리얼

profile
memories Of A front-end web developer

0개의 댓글