13. 이터러블

양희준·2022년 1월 15일
0

JavaScript Info

목록 보기
13/19
post-thumbnail

📌 13-1 이터레이션 프로토콜이란?

ES6에서 도입 순회 가능한 자료구조를 만들기 위해 정의한 프로토콜이다. ES6전에는 약속된 순회 프로토콜이 없고 각각의 방법으로 순회하였지만 순회 가능한 자료구조를 이터레이션 프로토콜을 준수하는 이터러블로 통일하여 사용한다.

  1. 이터레이션 프로토콜 규약
  • 객체가 이터레이션이 가능해야 한다.
  • 이터레이션 함수를 갖고 있어야 한다.
  • 프로토콜이기 때문에 프로토콜을 준수하면 이터레이션 할 수 없는 객체도 이터레이션이 가능하다.
    📃 여기서 객체란 빌트인 생성자 함수로 생성된 인스턴스들을 총칭한다.
  1. 이터레이션 프로토콜
  • 이터러블: Symbol.iterator 프로퍼티를 가지고 있다.
  • 이터레이터: Symbol.iterator 메소드를 호출하면 이터레이터를 반환한다. 이터레이터는 next 메소드를 가지고 있다.
    📃 이터레이션 프로토콜 안에 이터러블 프로토콜과 이터레이터 프로토콜이 포함되어있다.

📌 13-2 이터러블 프로토콜

Symbol.iterator 메소드를 가지고 있어야 이터러블이다.

const obj = {}
const arr = [];
// 문자열과 숫자도 프로토타입을 확인하기 위해서 인스턴스로 생성한다.
const str = new String("Hello");
const num = new Number(123);
// 사진 1번
console.log(obj);
// 사진 2번
console.log(arr);
// 프로토타입에 Symbol.iterator이 존재한다.
console.log(str);
// 프로토타입에 Symbol.iterator이 존재하지 않는다.
console.log(num);

html

html

🔥 obj에서는 프로토타입 안에 Symbol.iterator가 없는걸 확인할 수 있다. 하지만 arr에서는 프로토타입 안에 Symbol.iterator가 존재한다. 그러므로 이터러블 프로토콜을 준수한다. str의 프로토타입에도 Symbol.iterator가 존재한다.

🧩 이터러블 확인하기

const num = [1,2,3,4];
// 이터러블 메소드를 사용한다.
const iteratorNum = num[Symbol.iterator]();
// 결과 : 프로토타입 안에 next 메소드를 가지고 있다.
console.log(iteratorNum);

🧩 자주사용하는 빌트인 이터러블 객체
아래의 빌트인 객체들은 이터러블 프로토콜을 규약을 준수한다.

  • Array
  • String
  • Map
  • Set
  • DOM (NodeList, HTMLCollection)

📌 13-3 이터레이터 프로토콜

Symbol.iterator 메소드를 호출하여 next 메소드를 가지고 있어야 이터레이터이다.

  • 값을 순서대로 생성하는 방법이다.
  • next 메소드를 호출하면 이터레이터 오브젝트를 반환한다.
  • { value: value, done: ture/false }의 형태로 이터레이터 오브젝트를 반환한다.
  • done의 값이 true이면 이터레이터를 종료한다.
const arr = [1,2,3,4];
// 이터레이터를 호출
const iterator = arr[Symbol.iterator]();
// 결과 : {value: 1, done: false}
console.log(iterator.next());
// 결과 : {value: 2, done: false}
console.log(iterator.next());
// 결과 : {value: 3, done: false}
console.log(iterator.next());
// 결과 : {value: 4, done: false}
console.log(iterator.next());
// 결과 : {value: undefined, done: true}
console.log(iterator.next());

📌 13-4 유사 배열과 이터러블의 차이점

// 유사 배열 생성
const arrLike = { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 };
const arr = [1, 2, 3, 4];
for (let i = 0; i < arr.length; i++) {
    // 결과 : 1, 2, 3, 4 출력
    console.log(arrLike[i]);
    // 결과 : 1, 2, 3, 4 출력
    console.log((arr[i]));
}
  • 유사 배열은 객체를 배열처럼 순회할 수 있는 형태를 뜻한다.
  • 유사 배열과 이터러블의 차이점은 유사 배열은 객체이기 때문에 이터러블 프로토콜을 준수해야 사용할 수 있는 for - of 문을 사용하지 못한다.
  • Array.from 메소드를 사용하면 유사 배열이랑 이터러블도 배열로 변환하여 배열의 메소드를 이용할 수 있다.
  • 유사 배열도 이터러블 프로토콜을 준수하면 for - of 문을 사용할 수 있다.

🧩 for (초기화 변수 of 이터러블) { ... }

const arr = [1, 2, 3, 4];
// for - of 문은 이터러블 프로토콜을 준수한 대상의 모든 요소를 순회한다.
for(let item of arr) {
    console.log(item);
}
const arrLike = { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 };
for(let item of arrLike) {
    // 결과 : Uncaught TypeError: arrLike is not iterable
    console.log(item);
}

🔥 유사 배열을 넣었더니 에러가 출력된다. 유사 배열은 객체이기 때문이다.

🧩 사용자 정의 이터러블 만들기

function ObjIteratorCreate(obj) {
  // 1 
    obj[Symbol.iterator] = function () {
      // 2
        const index = Object.keys(obj).filter((item) => item !== "length");
        // 3
        let start = 0;
        let end = index.length;
        // 4
        return {
          // 5
            next () {
                let done = false;
                // 6
                if(start >= end) done = true;
                // 7
                return {
                    done : done,
                    // 8
                    value : obj[index[start++]]
                }
            }
        }
    }
}
const arrLike = { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 };
ObjIteratorCreate(arrLike);
const a = arrLike[Symbol.iterator]();
// 결과 : {done: false, value: 1}
console.log(a.next());
// 결과 : {done: false, value: 2}
console.log(a.next());
// 결과 : {done: false, value: 3}
console.log(a.next());
// 결과 : {done: false, value: 4}
console.log(a.next());

📃 ObjIteratorCreate 함수 설명
1. obj가 들어오면 Symbol.iterator 이름의 메소드를 생성한다.
2. index를 추출 객체의 키값을 배열로 만든뒤 유사 배열인지 확인하기위해서 length 제거한다.
3. 순회를 위한 초기화 변수 2개 설정
4. 이터레이터 프로토콜을 준수하기위해 객체를 반환한다.
5. next 함수를 반환한다.
6. start 가 end 보다 크거나 같으면 true로 바꿔서 이터러블 종료
7. 이터레이터 객체를 반환
8. 객체에서 키를 index로 설정하고 index는 지금 배열이므로 next함수가 실행될 때 마다 start를 1씩 증가시켜서 index의 요소들을 꺼내온다.

🧩 Array.from("이터러블, 유사배열", [ 모든 요소에 대해 실행할 Mapping 함수 ], [thisArg])

const arrLike = { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 };
// 유사 배열을 Array.from 메소드를 사용해서 배열로 변환시킨다.
const newArr = Array.from(arrLike, (item, index) => {
  /* Mapping 함수는 newArr의 요소와 인덱스의 대한 결과를 새롭게 반환한다.
    결과 : 
    실행 : 1 0
    실행 : 2 1
    실행 : 3 2
    실행 : 4 3
  */
    console.log(item, index);
    return item;
});
// 결과 : 1, 2, 3, 4
newArr.forEach((item) => console.log(item));

🔥 두 번째 요소로 들어가는 Mapping 함수는 Array.prototype.map 메소드와 비슷하다고 생각하면 된다. return 값으로 새로운 요소를 반환시켜준다.

🔥 Array.from 메소드를 사용하는 이유는 이터러블이나 유사 배열을 배열로 변환시켜 배열의 메소드를 사용하기 위해서이다.

📌 13-5 Array.from 메소드 사용예제

🧩 배열 초기화

// 1차원 배열 초기화 : 배열의 길이가 10, 안의 요소들 전부를 0으로 가진 배열
const arr1 = Array.from({length : 10}, () => 0);
// 2차원 배열 초기화 : 10 * 10 2차원 배열 안의 요소들 전부를 0으로 가진 배열
const arr2 = Array.from({length : 10}, () => Array.from({ length: 10 }, () => 0));
console.log(arr1);
console.table(arr2);

🧩 Set, Map 자료구조의 Array 메소드 사용

const arr = [1,1,1,1,3,4,5];
// 중복된 요소를 제거하기 위해서 자료구조 Set을 사용
const mySet = new Set();
// mySet에 arr의 모든 요소들을 순회하면서 add
arr.forEach((item) => mySet.add(item));
// mySet의 요소들을 배열로 변환
const newArr = Array.from(mySet);
// 배열 메소드 사용이 가능함
console.log(newArr.indexOf(5));

📌 13-6 스프레이드 문법이란?

const arr = [1,2,3,4];
// 결과 : 1 2 3 4
console.log(...arr);
const arr = [1,2,3,4];
console.log(...arr);
// 에러 출력 : 스프레이드 문법은 결과는 값이 아니다.
const spread = ...arr;
console.log(spread);
const arr = [1,2,3,4];
console.log(...arr);
// 펼친 요소들을 배열에 담아준다. 이제는 배열에 담아준거기 때문에 값이다.
const spread = [...arr];
console.log(spread);
  • 해당 대상의 각각의 요소들을 분산시켜 개별적인 값으로 만드는 문법이며 스프레이드 문법을 사용할 수 있는 대상은 이터러블 프로토콜을 준수한 대상이여야 한다.
  • 스프레이드 문법을 사용하 요소들을 값으로 반환하는것이 아니라 목록을 펼치는 형태이다.

📌 13-7 스프레이드 문법의 종류

1. 배열

const arr = [1,2,3,4];
const copyArr = [...arr];
arr[0] = 0;
// 결과 : [1,2,3,4]
console.log(copyArr);

📃 스프레이드 문법으로 배열을 만드는 경우 얇은 복사가 된다.

2. 문자열

const str = "onetwothree";
const copyStr = [...str];
// 결과 : ['o', 'n', 'e', 't', 'w', 'o', 't', 'h', 'r', 'e', 'e']
console.log(copyStr);

📃 문자열을 각각의 문자단위로 전개한다.

3. 객체

const obj = {
    0: 'a',
    1: 'b',
    2: 'c'
};
const newObj = {...obj};
// 결과 : {0: 'a', 1: 'b', 2: 'c'}
console.log(newObj);
const obj = {
    0: 'a',
    1: 'b',
    2: 'c'
};
const newObj = [...obj];
// 결과 : Uncaught TypeError: obj is not iterable
console.log(newObj);

📃 객체는 이터러블이 아니므로 스프레이드 문법을 사용할 수 없지만 자바스크립트에서는 객체도 스프레이드 문법을 객체 스프레이드 문법으로 따로 만들어서 사용할 수 있게 한다. 하지만 이터러블이 아니므로 다른 스프레이드 문법들 처럼 사용할 수 없고 객체끼리만 사용이 가능하다.

4. 함수

function add(one, ...two) {
    // 결과 : [2, 3, 4] *배열의 형태로 오게 된다.*
    console.log(two);
    let add = one;
    two.forEach((item) => add += item);
    return add;
}
console.log(add(1, 2, 3, 4));

5. rest 파라미터

function add(a, b, c, d) {
    return a + b + c + d;
}
const arr = [2, 3, 4];
console.log(add(1, ...arr));
profile
JS 코린이

0개의 댓글