Today I Learnd

Chipmunk_jeong·2021년 5월 5일
0

TIL

목록 보기
45/62
post-thumbnail

함수형 자바스크립트

평가

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


일급

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

const a = 10;
const add10 = a => a + 10;
const r = add10(a); // 20

일급 함수

-> 함수를 으로 다룰 수 있다.
-> 조합성과 추상화의 도구이다.

const add5 = a => a + 5;
console.log(add5); // a => a + 5 (f)
console.log(add5(5)); // 10;

const f1 = () => () => 1;
console.log(f1()); // () => 1 (f)
const f2 = f1();
console.log(f2); // () => 1 (f)
console.log(f2()); // 1

고차 함수

-> 함수를 값으로 다루는 함수

1) 함수를 인자로 받아서 실행하는 함수 (callback)
2) 함수를 만들어 리턴하는 함수 (curry)
-> 클로저를 만들어 리턴하는 함수

// callback exam
const apply1 = f => f(1);
const add2 = a => a + 2;
console.log(apply1(add2)); // 3

const times = (f, n) => {
 for(let i=0; i<n; i++) {
   f(i);
 }
};

times(console.log, 3); // 0, 1, 2
times(a => console.log(a + 10), 3); // 10, 11, 12
// curry exam
const addMaker = a => b => a + b;
const add10 = addMaker(10);
console.log(add10);// b => 10 + b; (f)
console.log(add10(5); // 15

이터러블(ES6)

리스트 순회

  • for i++
  • for of
const list = [1, 2, 3];

// es5
for(var i=0; i<list.length; i++_ {
  console.log(list[i]);
}

// es6
for(let el of list) {
  console.log(el);
}

Array & Set & Map

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

const set = new Set([1, 2, 3]);
for(const a of set) console.log(a);

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

for...of는 어떤원리로 돌아갈까?
키워드는 Symbol.iterator

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

위에서 Symbol.iterator를 null을 줌으로써 반복문에서 에러가 발생한다. 이는 Set, Map에도 동일하다.
이걸 통해서 for...of반복은 위의 속성과 관계가 있다는것을 알 수 있다.

이터러블/이터레이터 프로토콜

  • 이터러블 : 이터레이터를 리턴하는 [Symbol.iterator]() 를 가진 값
  • 이터레이터: {value, done } 객체를 리턴하는 next()를 가진 값
  • 이터러블/이터레이터 프로토콜: 이터러블을 for...of, 전개 연산자 등과 함께 동작하도록한 규약
arr[Symbol.iterator]; // values() { [native code] }
let iterator = arr[Symbol.iterator]();
iterator.next(); // {value: 1, done: false}
iterator.next(); // {value: 2, done: false}
iterator.next(); // {value: 2, done: false}
iterator.next(); // {value: undefined, done: true}

위에서 심볼 이터레이터를 실행시켜 리턴받은 이터레이터를 통하여
next()를 호출했을 때 value의 값과 done의 값을 가지는 객체가 리턴된다.
그리고 이 value의 값들은 배열의 요소들이고 모든 요소들을 다 가져왔을 때 done은 true가 된다.
for...of나 전개 구문에서 원리가 이런것이다.
1. arr[Symbor.iterator]()를 실행하여 이터레이터 객체 리턴
2. next()메서드를 통하여 요소값으로 받아온 value를 넘겨줌
3. done이 true이면 반복문을 빠져나옴

실제로 아래와 같은 코드를 작성하면 반복문이 생각한것보다 덜 돈다.

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

for(const a of iterator) {
  console.log(a); // 3이라는 요소 한번만 찍힌다.
}

for...of문에서 이터레이터 next()를 호출하는것을 이미 2번이나 미리 실행시켰기 때문에 실제적으로 반복문에서는 3이라는 숫자 한번만 찍히게 된다.

사용자 정의 이터러블

const iterable = {
  [Symbol.iterator]() {
    let i = 3;
    return {
      next() {
        return i == 0 ? {done: true} : { value: i-- , done: false }
      },
      [Symbol.iterator]() { return this; }
    }
  }
};

let iter = iterable[Symbol.iterator]();
console.log(iter.next()); 
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());

이처럼 사용자 정의 이터러블 객체를 만들때에 중요하게 생각해야될 것은 [Symbol.iterator]를 만들어 줘야한다는 것이다.
또한 리턴되는 이터러블에도 이 심볼이터레이터 메서드가 있어야한다.

웹브라우저 환경, 오픈라이브러리 등등 많은 곳에서 이 프로토콜을 이용하고 있다.

전개 연산자

const a = [1, 2];
a[Symbol.iterator] = null;
console.log(...a); // error

전개 연산자 또한 이터레이터객체를 사용하는 것이다.


... 솔직히 말해서 당장 100%이해가 되지는 않는다. 하지만 좀더 다양하게 경험을하고 다시한번 이 개념을 봤을 때 더 많은것이 보이게끔 성장하고 다시 공부해볼것이다.

profile
Web Developer

0개의 댓글