본문 바로가기
JavaScript

[FP&ES6+] 리스트 순회와 이터러블, 이터레이터

by _sweep 2021. 10. 29.

 

함수형 프로그래밍과 JavaScript ES6+ 강의를 듣고 정리한 내용입니다.

 

 리스트 순회

기존 ES5 문법에서의 리스트 순회는 for문을 이용했다. 

 

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

// output
// 1
// 2
// 3

const str = "abc";
for(var i = 0; i < str.length; i++){
	console.log(str[i]);
}
// output
// a
// b
// c

 

i의 값을 증가시키면서 대상의 i번째 요소에 접근하는 것이다.

 

ES6+에서는 for...of문이 추가되었다.

 

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

// output
// 1
// 2
// 3

const str = "abc";
for(const a of str){
	console.log(a);
}

// output
// a
// b
// c

 

for...of문 문법이 추가됨으로써 대상을 순회하기가 더욱 간편해졌다.

 

 

✅ for of문의 원리

for...of문의 원리를 알기 전 js에는 array, set, map이라는 내장 객체가 있다.

이 내장 객체들은 모두 for...of문으로 내부 순회가 가능하다. 

이중 array는 위의 인덱스로 접근하는 것처럼 arr[1], arr[2] 등으로 값을 확인할 수 있지만 set, map은 set[1], map[2] 등으로 값에 접근하려고 하면 undifined가 뜨면서 접근이 불가능하다.

그런데 for...of문은 어떻게 set, map의 내부를 순회할 수 있을까?

 

답은 array, set, map이 이터러블/이터레이터 프로토콜을 따르고 있기 때문이다.

 

여기서 이터러블이란 iterator를 리턴하는 [Symbol.iterator]()를 가진 값으로 array, set, map을 이터러블이라 할 수 있다.

이터레이터는 {value, done} 객체를 리턴하는 next()를 가진 값이다.

이터러블/이터레이터 프로토콜은 이터러블을 for...of, 전개연산자등과 함께 동작하도록 한 규약이다.

 

const arr = [1, 2, 3];
let iterator = arr[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

// output
// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
// { value: undefined, done: true }

 

arr은 iterator를 리턴하는  [Symbol.iterator]메소드를 가지고 있고 이를 iterator라는 변수에 담아 next 메소드를 사용함으로써 내부를 순회하고 있다.

내부를 순회할 때는 done이 false였다가 내부 순회가 끝나자 done이 true로 바뀌는 것을 확인할 수 있다.

 

즉, for...of문은 이터러블/이터레이터 프로토콜에 따라 iterator를 이용해 내부를 순회하며 done이 false면 value를 출력하고 true이면 순회를 끝내는 작업을 하고있는 것으로 볼 수 있다.

 

 

 사용자 정의 이터러블

이터러블은 이터레이터를 리턴하는 [Symbol.iterator]()를 가진 값이라고 했다.

따라서 이터러블을 만들기 위해서는 다음과 같은 규칙이 필요하다.

  • [Symbol.iterator]()를 가지고 있을 것.
  • next()를 통해 내부에 접근할 것.
  • 내부 순회가 끝나면 done = true, 끝나기 전이면 {value, done: false} 객체를 리턴할 것.
  • iterator의 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 iterable){
	console.log(a);
}

// output
// 3
// 2
// 1

for(const a of iterator){
	console.log(a);
}

// output
// 3
// 2
// 1

 

 

 

 전개연산자

전개연산자도 이터러블/이터레이터 프로토콜을 따른다.

그렇기 때문에 다음과 같은 결과를 얻을 수 있다.

 

const a = [1, 2];
console.log([...a, ...[3, 4]])

// output
// [1, 2, 3, 4]

 

 

 

 

 

댓글