본 시리즈는 인프런 강의 함수형 프로그래밍과 JavaScript ES6+ ( 지식 공유자 : 유인동 님 ) 의 강의를 수강하면서 내용을 제 방식대로 포스팅하는 글입니다.
함수형 프로그래밍과 JavaScript ES6+ - 인프런 | 강의
ES6+와 함수형 프로그래밍을 배울 수 있는 강의입니다. 이 강좌에서는 ES6+의 이터러블/이터레이터/제너레이터 프로토콜을 상세히 다루고 응용합니다. 이터러블을 기반으로한 함수형 프로그래밍,
www.inflearn.com
이 내용은 이전 게시물과 이어지는 내용입니다.
이전 게시물에서 만들어본 map 함수는 이터러블 프로토콜을 따르기 때문에 다형성이 굉장히 높다
먼저, Array.prototype.map 함수를 이용해 querySelectorAll 을 통해 생긴 배열을 map() 함수를 이용해보자
const map = (f, iter?) => {
let res = [];
for (const a of iter) {
res.push(f(a));
}
return res;
};
console.log(document.querySelectorAll("*")); // NodeList(7) [html, head, body ...]
// 이런 형태의 값을 map() 함수를 통해 내부에 있는 값을 수집해보려고할때
// map() 함수를 사용해보면 에러가난다.
// 에러에 나온 내용처럼, NodeList 에는 map() 함수가 없다.
console.log(document.querySelectorAll("*").map((el) => el.nodeName));
// TypeError : document.queryS.... map is not a function
console.log([1, 2, 3].map((a) => a + 1)); // [2, 3, 4]
위와 같은 에러가 생기는 이유는, NodeList 는 Array 를 상속 받은 객체가 아니기 때문에,
프로토타입에 map 함수가 구현이 안되어있어서 생기는 에러다. (프로토타입 이란? <- 추후 포스팅 예정.)
프로토타입에 대한 내용은 https://poiemaweb.com/js-prototype 이곳에 개념 설명이 잘 되어있다.
Prototype | PoiemaWeb
자바스크립트의 모든 객체는 자신의 부모 역할을 하는 객체와 연결되어 있다. 그리고 이것은 마치 객체 지향의 상속 개념과 같이 부모 객체의 프로퍼티 또는 메소드를 상속받아 사용할 수 있게
poiemaweb.com
__proto__ 접근자 프로퍼티를 통해 콘솔창에서 열어봐도 실제로 map 함수가 들어있지 않다.
직접 구현한 map 함수를 사용해보면, 잘 동작한다.
console.log(map((el) => el.nodeName, document.querySelectorAll("*"))); // ['HTML', 'HEAD', 'BODY' ...]
그러한 이유는 document.querySelector 가 이터러블 프로토콜을 따르고 있기 때문이다.
const it = document.querySelectorAll("*")[Symbol.iterator]();
console.log(it); // [Function Iterator]
console.log(it.next()); // {value: html, done: false}
console.log(it.next()); // {value: head, done: false}
console.log(it.next()); // {value: body, done: false}
// 이렇게 때문에 이터러블 프로토콜을 따르는 for...of 문을 통해 순회가 가능한 것이다.
// 따라서 우리가 직접 구현한 map 함수는 이터러블 프로토콜을 따르는 많은 값들을 사용할수 있다.
직접 구현한 map 함수는 제너레이터를 통해서도 사용이 가능하다
function* gen() {
yield 2;
yield 3;
yield 4;
}
console.log(
map((a) => a * a),
gen()
); // [4, 9, 16]
그렇다는 얘기는, 사실상 이 map 함수의 경우 굉장히 다형성이 높다는것을 알수있다.
이터러블 프로토콜을 따르는 모든 값들, 문장 역시도 map 을 사용할수가 있다.
제너레이터 함수의 결과들 에 대해서도 map 을 할수 있기 때문에, 사실상 거의 모든것들을 map 을 할수 있다고 볼수있다.
// if 문이 있어도 사용할수 있게된다.
function* gen() {
yield 2;
if (false) yield 3;
yield 4;
}
console.log(
map((a) => a * a),
gen()
); // [4, 16]
위에서 사용했던 document.querySelector 는 Web API 이고, 이 API 들도 이터러블 프로토콜을 따른다.
이미 많은것들이 이터러블 프로토콜을 따르고 있으며, 앞으로도 계속 그렇게 될것이다.
따라서 이터러블 프로토콜을 따른다면, 앞으로도 생기는 많은 헬퍼 함수들과의 조합성도 좋아진다는 이야기 이다.
우리가 만들어본 map 함수는 프로토타입 기반으로, 클래스 기반으로 어떤 뿌리를 가진, 어떤 카테고리 안에 있는 값만 사용할수 있는 기법보다 훨씬 유연하고 다형성이 높다고 볼수 있다.
'Javascript' 카테고리의 다른 글
filter 함수를 구현해보자 - JS ES6+ 함수형 프로그래밍 - 14 (1) | 2022.09.12 |
---|---|
JS - 이터러블 프로토콜을 따른 map 의 다형성 (2) - JS ES6+ 함수형 프로그래밍 - 13 (2) | 2022.09.11 |
map 함수를 구현해보자 ( feat.이터러블 프로토콜 ) - JS ES6+ 함수형 프로그래밍 - 11 (0) | 2022.09.11 |
for...of, 전개 연산자, 구조 분해, 나머지 연산자 - JS ES6+ 함수형 프로그래밍 - 10 (1) | 2022.09.11 |
JS - 제너레이터를 이용한 홀수 반환 함수 - JS ES6+ 함수형 프로그래밍 - 9 (0) | 2022.09.09 |