혼자 적어보는 노트

프로그래머스 데브코스 TIL - Day 6 본문

스터디

프로그래머스 데브코스 TIL - Day 6

jinist 2022. 3. 28. 22:20

 학습 목차

- [Day 6] JavaScript 주요 문법 (6)

- 함수형 프로그래밍과 ES6+ (1)

 

✅ 새롭게 학습한 부분

- 너비 우선 탐색

- 깊이 우선 탐색

- 함수형 프로그래밍

- 평가/일급/일급함수/고차함수

- iterable/iterator

 


🔗 자료구조 알고리즘

 

너비 우선 탐색(BFS)

- 그래프 탐색 알고리즘으로 같은 깊이에 해당하는 정점부터 탐색하는 알고리즘
- Queue를 이용하여 구현할 수 있다.
- 시작 지점에서 가까운 정점부터 탐색한다.
- V가 정점의 수, E가 간선의 수일 때 BFS의 시간복잡도는 O(V+E)이다


깊이 우선 탐색(DFS)

- 그래프 탐색 알고리즘으로 최대한 깊은 정점부터 탐색하는 알고리즘
- Stack을 이용하여 구현할 수 있다
- 시작 정점에서 깊은 것 부터 찾는다
- V가 정점의 수, E가 간선의 수일 때 BFS의 시간복잡도는 O(V+E)이다


그리디 알고리즘

- 매 선택에서 이 순간 가장 최적인 답을 선택하는 알고리즘
- 최적 해를 보장해주지 않는다.
- 보통 최적 해를 구하는 알고리즘보다 빠른 경우가 많다.
- 크루스칼, 다익스트라 알고리즘 등에 사용된다.
- 직관적인 문제 풀이에 적합하다.

 


💻 함수형 프로그래밍

 

평가

- 코드가 계산(Evaluation)되어 값을 만드는 것

 

일급

- 값으로 다룰 수 있다.
- 변수에 담을 수 있다.
- 함수의 인자로 사용될 수 있다.
- 함수의 결과로 사용될 수 있다.

 

일급함수

- 함수를 값으로 다룰 수 있다.
- 함수의 결과 값으로 함수를 사용할 수 있다.
- 조합성과 추상화의 도구.

const func1 = () => () => 10;

const func2 = func1();

console.log(func2); // () => 10
console.log(func2()); // 10

 

고차함수

- 일급 함수의 성질을 이용해서 함수를 값으로 다루는 함수

1) 함수를 인자로 받아서 실행하는 함수 (안에서 실행한다)

const func = f => f("Jay");

const hello = name => "Hello " + name;

console.log(func(hello)); // Hello Jay

2) 함수를 만들어 리턴하는 함수

const func = f => name => f + name; // f를 기억하고 있는 클로저를 리턴
const func2 = func("Hello ");

console.log(func2("Jay")); // Hello Jay

 

 

iterable/iterator protocol

: 이터러블을 for ...of, 전개 연산자 등과 함께 동작하도록 한 규약.

 

iterable

iterator를 return하는 Symbol.itrator 메소드를 가진 값.

iterable은 symbol.iterator를 실행했을 때 iterator를 return 하는 값.

 

iterator

- {value, done} 객체를 return하는 next()메소드를 가진 값

- value와 done이라는 키에 해당하는 객체를 return하는 next()를 가진 값

 

 

 

정의만 읽었을 땐 이해가 확 와닿지 않아서 직접 쳐보면서 이해해보았다.. 😓

 

 

즉, for of로 반복문을 돌릴 수 있는 것들은 모두 iterable.

array는 for.. of문으로 반복을 돌릴 수 있고 arr[Symbol.iterator]값에 함수가 들어 있다. == iterable

const arr = [1, 2, 3, 4];

arr[Symbol.iterator] = null;
for (const a of arr) console.log(a); // Uncaught TypeError: arr is not iterable

Symbol.iterator에 있는 함수를 없애면 for ..of 문이 실행되지 않는다.

 

const arr = [1, 2, 3, 4];

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

console.log(iterator); // Array Iterator {}
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {value: 2, done: false}
console.log(iterator.next()); // {value: 3, done: false}

 

iterable인 Array는 Symbol.iterator를 가지고 있는데 이것의 반환 값에는 next()가 있고,

for ...of는 next()의 value값을 반환해 준다.

 

 

map과 set 또한 마찬가지 === iterable 프로토콜을 따르고 있다

const set = new Set([1, 2, 3]);

for (const a of set) console.log(a);
// 1
// 2
// 3

const map = new Map([["a", 1], ["b", 2], ["c", 3]]);

for (const a of map) console.log(a);
// ['a', 1]
// ['b', 2]
// ['c', 3]

 

map의 keys(), values(), entries()는 iterator를 반환한다

 

const map = new Map([["a", 1], ["b", 2], ["c", 3]]);

console.log(map.values()); //MapIterator {1, 2, 3}

let iterator = map.values();
console.log(iterator[Symbol.iterator]); // ƒ [Symbol.iterator]() { [native code] }

//iterator는 내부에 또 Symbol.iterator를 가지고 있다. (자기 자신)

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

console.log(iterator2.next()); // {value: 1, done: false}
console.log(iterator2.next()); // {value: 2, done: false}
console.log(iterator2.next()); // {value: 3, done: false}

Symbol.iterator의 반환값에 next()이 있기 때문에 for ...of 에서 value를 받을 수 있다.

 

 

well-formed iterable

const arr = [1, 2, 3];
let iterator = arr[Symbol.iterator](); // Symbol.iterator를 가진다

iterator.next(); // next()를 사용할 수 있다.

for (const a of iterator) console.log(a); // next에 이어서 for ...of를 사용할 수 있다.
// 2
// 3

console.log(iterator); // Array Iterator {}
console.log(iterator[Symbol.iterator]() == iterator); // true

itarable은 Symbol.iterator를 가지고 있고

Symbol.iterator가 반환한 iterator에 next() 메소드가 있으며

Symbol.iterator가 반환한 iterator로 for ..of 순회가 가능 해야 한다.

 

또한 iterator가 자기 자신을 반환하는 Symbol.iterator를 가지고 있다면

well-formed iterable이라고 한다.

 

사용자 정의 iterable

iterable을 직접 만들 수도 있다.

const iterable = {
  [Symbol.iterator]() {
    let i = 3;
    return {
      next() {
        return i == 0 ? { done: true } : { value: i--, done: false };
      },
      [Symbol.iterator]() { return this; } // 자기 자신을 반환하는 well-formed iterable
    };
  },
};

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

console.log(iterator.next()); // {value: 3, done: false}
console.log(iterator.next()); // {value: 2, done: false}
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {done: true}

for (const a of iterable) console.log(a); // 가능

 

 

전개연산자 (Spread Operator)

iterable/iterator protocol을 따르고 있는 값들을 펼쳐준다.

즉, Symbol.iterator을 가진 아이들만 펼쳐주는 것이였다.. 😱

const array = [1, 2, 3];

array[Symbol.iterator] = null;

console.log([...array]); // test.js:5 Uncaught TypeError: array is not iterable

 

 


✍ 느낀점

 

아직도 너무 어려운 자료구조와 알고리즘의 세계..

하나의 자료구조와 알고리즘들을 익히기 위해서는 문제를 더 여러개 풀어봐야 할 것 같다.

꾸준히 반복적으로 해볼 예정이다. 🔥🔥

그리고 이번 주 부터 함수형 프로그래밍에 대한 강의를 함께 보게 되었는데

이전에 제너레이터를 처음 접하면서 알게 되었지만,

다른 것들에 치여서 미뤄왔던 iterable과 iterator에 대해 알게 되었다.

처음엔 헷갈려서 무슨 말이지..? 했는데 직접 쳐보면서 해보니 원리를 알아가는 것이 재미있었다.

리액트를 하면서 에러 창에서 종종 보았던 is not iterable.. 이제는 조금 친근해 진 것 같다!

 

Comments