회고록 블로그

[공부 필기] JavaScript 문법 공부 26일차 (2) 본문

2. 프로그래밍 언어 공부/JavaScript

[공부 필기] JavaScript 문법 공부 26일차 (2)

김간장 2022. 5. 27. 23:53

※ 필자는 초초초보자입니다.

※ 틀린 내용에 대한 피드백은 언제든지 환영합니다.

 

 

공부하고 있는 자료 : modern JavaScript tutorial 

https://ko.javascript.info/iterable

 

iterable 객체

 

ko.javascript.info

 

✅ iterable 객체

- 반복 가능한 객체 : iterable 객체

- 배열을 일반화한 객체이다.

   ► iterable 객체의 대표적인 예가 [배열], [문자열]이다.

- 이 이터러블 이라는 개념을 사용하면 for...of 반복문을 적용할 수 있다.

 

- 이터러블을 배우는 이유는

   배열이 아닌 객체라도 어떤 것들의 컬렉션(목록, 집합 등)을 나타내고 있는 경우

   for...of문을 적용할 수 있으면 컬렉션을 순회하는데 편하기 때문이다.

   /* 배열이 아니더라도 for...of가 적용될 수 있도록 해보는게 목표 */

 

✅ Symbol.iterator

- 이터러블 객체를 직접 만들어보자

- 여기 for...of문을 적용하기에 적합해 보이는 배열이 아닌 객체가 있다.

let range = {
	from: 1,
	to: 5
};

 

- range를 이터러블로 만들려면(=for...of가 동작하도록 하려면)

   객체에 Symbol.iterator라는 특수 내장 심볼의 메서드를 추가해야한다.

 

- for...of가 시작되자마자 Symbol.iterator를 호출하는데 (없으면 에러 발생) 이 Symbol.iterator에는 다음과 같은 작업이 구현되어야 한다.

   1) Symbol.iterator는 반드시 이터레이터(=next라는 메서드가 있는 객체이다)를 반환해야한다.

   2) 이후 for...of는 반환된 객체(이터레이터)만을 대상으로 동작한다.

   3) for...of에 다음 값이 필요하면, for...of는 이터레이터의 next() 메서드를 호출한다.

   4) next() 메서드의 반환 값은 {done: Boolean, value: any}와 같은 형태이어야 한다.

   5) done=true는 반복이 종료됐음을 의미한다.

   6) done=false일 땐, value에 다음 값이 저장된다.

 

- 그래서 코드로 구현해보면 다음과 같다!

let range = {
	from: 1,
	to: 5
};

range[Symbol.iterator] = function() {
	// 1. Symbol.iterator는 반드시 이터레이터(=next라는 메서드가 있는 객체이다)를 반환해야한다.
	return {
		current: this.from,
		last: this.to,
		// next() 메서드의 반환 값은 {done: Boolean, value: any}와 같은 형태이어야 한다.
		next() {
			if (this.current <= this.last)
				return {done: false, value: this.current++ }; // done=false일 땐, value에 다음 값이 저장된다.
			else
				return { done: true }; // done=true는 반복이 종료됐음을 의미한다.
		},
	};
};


//0. for...of가 시작되자마자 Symbol.iterator를 호출한다.
for (let num of range) {
	console.log(num);
}

 

- 이터러블 객체의 핵심은 [관심사의 분리(SoC)] 라고 한다.

   ► range 객체에는 next() 메서드가 없다.

   ► 대신 range[Symbol.interator]()를 호출해서 만든 '이터레이터' 객체와 이 객체의 메서드 next()에서 반복에 사용될 값을 만들어낸다.

- 이렇게하면 이터레이터 객체와 반복 대상인 객체를 분리할 수 있다.

   ► 물론 분리하지 않고 합쳐서, range 자체를 이터레이터로 만들 수도 있다.

 

- 단점은 for...of 반복문을 하나의 객체에 동시에 사용할 수 없다.

   ► 이터레이터(객체 자신)가 하나뿐이라 두 반복문이 반복 상태를 공유하기 때문

 

✅ 문자열은 iterable

- 배열 뿐만 아니라 문자열도 이터러블이다.

let str = "✅‣";

for (let char of str) {
	console.log(char);
}

 

✅ iterator를 명시적으로 호출하기

- 직접 이터레이터를 호출해서 순회를 해보자.

   ► done과 value를 이용해서 수동으로 값을 가져온다.

   ► 이렇게 사용하면 반복을 시작했다가 잠시 멈춰 다른 작업을 하다가 다시 반복을 시작하는 등 반복 작업을 쪼갤 수 있다.

let str = "✅✅✅✅";

let iterator = str[Symbol.iterator]();

console.log(iterator); // Object [String Iterator] {}

while (1) {
	let char = iterator.next();
	if (char.done) break ;
	console.log(char.value); // 한글자씩 출력
}

 

✅ 이터러블과 유사 배열

- 이터러블 vs 유사배열

   ► 이터러블(iterable) : Symbol.iterator 메서드가 구현된 객체이다.

   ► 유사배열 : 인덱스, length 프로퍼티가 있어서 배열처럼 보이는 객체이다.

 

- 브라우저 등 호스트 환경에서 이터러블 객체, 유사배열 객체, 이터러블 객체+유사배열 객체에 다 해당하는 객체를 만날 수 있다.

   ► 이터러블 객체+유사배열 객체에 다 해당하는 객체의 예

        → for...of를 사용할 수 있으면서 length 프로퍼티/숫자 인덱스가 있는 [문자열]

 

- 이터러블, 유사 배열은 대개 배열이 아니기 때문에 push, pop 등 메서드를 지원하지 않는다.

   ► 그렇다면 이터러블, 유사 배열에서 push, pop과 같은 메서드를 적용할 수 있을까..?

 

✅ Array.from

- 범용 메서드인 Array.from

 

- 이터러블이나 유사 배열을 받아 진짜 Array를 만들어준다.

   ► 이 과정을 거치면 이터러블이나 유사 배열에 배열 메서드를 사용할 수 있다.

// 유사배열
let arrayLike = {
	0: "Hello",
	1: "World",
	length: 2
};

let arr = Array.from(arrayLike);
console.log(arrayLike); //{ '0': 'Hello', '1': 'World', length: 2 }
console.log(arr); // [ 'Hello', 'World' ]
console.log(arr.pop()); //World

- Array.from은 객체를 받아 이터러블이나 유사 배열인지 조사를 한다.

   ► 이터러블 혹은 유사 배열이면, 새로운 배열을 만들고 객체의 모든 요소를 새로운 배열에 복사한다.

 

- Array.from 메서드는 다음과 같은 인자를 전달한다.

Array.from(obj[, mapFn, thisArg])

- 여기에서 mapFn(매핑 함수)와 thisArg는 선택 사항이다.

   ► mapFn을 전달하면, 첫번째 인자로 전달한 객체(이터러블 or 유사 배열)의 요소를 추가하기 전에 각 요소를 대상으로 mapFn을 적용한다.

   ► 즉, 새로운 배열의 요소는 mapFn을 적용한 값이 되는 것이다.

 

- Array.from을 이용하면 문자열을 배열로 만들 수도 있다.

 

 

Comments