211019 TIL '함수형 자바스크립트 프로그래밍' 스터디

» 2막, TIL (Today I Learned), 스터디

‘함수형 자바스크립트 프로그래밍’ 스터디

회사 직원분들과 가끔씩 도서 스터디를 진행하는데, 이번엔 유인동 저자의 함수형 자바스크립트 프로그래밍 교재를 같이 공부하기로 했다. 각자 정해진 분량까지 읽고, 이야기를 나누는 형태로…

간단히 정리한 내용을 같이 올린다.

교재 예제 코드 교재 코드가 올라와있어서 코드를 직접 돌려볼 때 편했다.

함수형 자바스크립트 소개

1.1 함수형 프로그래밍

  • 커링
  • 부분 적용
  • 함수 리턴 하는 함수 (addMaker)
  • 값으로서의 함수클로저를 이용한 함수형 자바스크립트 스타일 ```js function addMaker(a) { return function(b) { return a + b; } } addMaker(10)(5); // 15

var add5 = addMaker(5); add5(3); // 8 add5(4); // 9

var add3 = addMaker(3); add3(3); // 6 add3(4); // 7



#### 1.2 함수형 자바스크립트의 실용성
- filter
    - 항상 동일하게 동작하는 함수 => 한 가지 로직
    - 동일한 인자가 들어오면 항상 동일하게 동작
- 함수형 프로그래밍에서는 항상 동일하게 동작하는 함수 를 만들고 보조 함수를 조합하는 식으로 로직을 완성한다
- 객체지향 ↔︎ 함수형 프로그래밍 이 아니다!
    - 지향점의 차이
- map 
  - 실행 결과로 바로 실행하기
- 화살표 함수

#### 1.3 함수형 자바스크립트의 실용성2
- filter → break 못씀 
    - for - break 함수로 대체 → 함수형이지 않음! → findByAge, findByName → findBy(key, list, val) 함수로? → 이것또한 한계가 있음. 객체의 메서드로 값을 얻어야 하는 경우 등엔 안됨 [p.16]
- 값에서 함수로 
  - find(list, predicate) → predicate(보조함수) === function
- 고차함수 : map, filter, find, findIndex, bvalue, bmatch
    - 함수를 인자로 받거나 함수를 리턴하는 함수 
    - Underscore.js 라이브러리의 함수들
- falsy values = false , undefined, null, 0, NaN, ""
- 함수 합성
    - 함수를 쪼갤수록 함수 합성은 쉬워진다 
    - 함수 합성으로 코드가 간결해지긴 하는데… 이해하는데 너무 오래걸리는건 아닐까? 
  - 더 작은 단위 → 재사용성
  - 제어문 < 함수, 값 < 함수, 연산자 < 함수


#### 1.4 함수형 자바스크립트를 위한 기초

- 일급함수(first-class), 클로저, 고차함수, 콜백패턴, 부분적용, arguments 객체, bind/call/apply

- 일급함수 
  - 함수 === 일급 객체, 일급 함수 (일급 === 값을 다룰 수 있다), 객체 === 일급 객체
    - 변수에 담을 수 있다
    - 함수/메서드의 인자로 넘길 수 있다
    - 함수/메서드에서 리턴할 수 있다 
  - 사실, 자바스크립트에서 모든 값은 일급. 일급함수는, 
    - 아무 때나(런타임에서도) 선언 가능 
    - 익명으로 선언 가능 
    - 익명으로 선언한 함수도 함수나 메서드의 인자로 넘길 수 있음
- 클로저 
  - 스코프 === 변수를 어디에서 찾을지 정한 규칙. 변수 참조

- 클로저 === 자신이 생성될 때의 환경을 기억하는 함수. 자신의 상위 스코프의 변수를 참조할 수 있다
- 자바스크립트의 모든 함수는 상위 스코프를 가지며, 모든 함수는 자신의 정의되는 순간의 실행 컨텍스트 안에 있다
- 클로저를 만들 함수가 myfn 이라면, myfn 내부에서 사용하고 있는 변수 중에 myfn 내부에서 선언되지 않은 변수가 있어야한다. 그 변수를 a라고 한다면, a라는 이름의 변수가 myfn을 생성하는 스코프에서 선언되었거나 알 수 있어야한다.
- 글로벌 스코프를 제외한 외부 스코프에 있었던 변수 중 클로저/참조되고 있지 않는 모든 변수는 실행 컨텍스트가 끝난 후 가비지 컬렉션 대상이 된다.
- 클로저 === 자신이 생성될 때의 스코프에서 알 수 있었던 변수 중 언젠가 자신이 실행될 때 사용할 변수들만 기억하여 유지시키는 함수
- 클로저 === 자신의 생성되는 스코프의 실행 컨텍스트에서 만들어졌거나 알 수 있었던 변수 중 언젠가 자신이 실행될 때 사용할 변수들만 기억하는 함수. 클로저가 기억하는 변수의 값은 언제든지 남이나 자신에 의해 변경될 수 있다.
- 언제쓰는가? not only for 은닉
    - 이전 상황을 나중에 일어날 상황과 이어 나갈 때
    - 함수로 함수를 만들거나 부분 적용을 할 때
    - 무조건 많이 사용해보라..!!

```js
var users = [
{ id: 1, name: "HA", age: 25 },
{ id: 2, name: "PJ", age: 28 },
{ id: 3, name: "JE", age: 27 }
];

$('.user-list').append(
_.map(users, function(user) { // (1) 이 함수는 클로저가 아니다.
var button = $('<button>').text(user.name); // (2)
button.click(function() { // (3) 계속 유지되는 클로저 (내부에서 user를 사용했다.)
if (confirm(user.name + "님을 팔로잉 하시겠습니까?")) follow(user); // (4)
});
return button; // (5)
}));

function follow(user) {
$.post('/follow', { user_id: user.id }, function() { // (6) 클로저가 되었다가 없어지는 클로저
alert("이제 " + user.name + "님의 소식을 보실 수 있습니다.");
});
}
  • 고차함수
    • 함수를 인자로 받아 대신 실행하는 함수
    • 함수를 리턴하는 함수
    • 함수를 인자로 받아 또 다른 함수를 리턴하는 함수
    • map, filter, reduce…
  • 콜백 함수라 잘못 불리는 보조 함수
    • 컨텍스트를 다시 돌려주는 역할. ex. 비동기가 일어나는 상황에서 돌아오기 위함
    • 인자로 사용된 모든 함수가 콜백함수인 것은 아님!
    • 콜백은 종료가 되었을때 한번만 실행 / iteratee(each), predicate(filter), listener등은 종료될때 실행되지 않으며 상황에 따라 여러번 실행되기도 함
  • partial
    • 일부 인자만 넣어두고 나중에 인자 채울 수 있도록

함수형 자바스크립트를 위한 문법 다시 보기

2.1 객체와 대괄호 다시보기

  • 객체와 key
    • {}안쪽 선언과 []안 선언 : []안에서는 함수 실행 가능
    • obj13[‘len’+’gth’] = 10 도 작동…
  • delete

2.2 함수 정의 다시 보기

  • 호이스팅
    • 변수, 함수가 어디에 선언되든지 해당 스코프 최상단에 위치하게 되어 동일 스코프 어디서든 참조할 수 있는 것
    • 선언한 적 없는 함수 실행 시 오류 메시지 => Uncaught ReferenceError : ~ is not defined
    • 초기화 되지 않은 상태에서 함수 실행 시 오류 메시지 => Uncaught ReferenceError : ~ is not a function
    • 변수 : 선언 단계와 초기화 단계가 구분 되어 있음
    • 선언과 초기화가 동시에 이루어지지 않음. 호이스팅에 의해 참조만 가능. 실행 불가
    • 함수는 선언과 동시에 초기화가 이루어지기 때문에 참조뿐 아니라 실행도 가능.
  • 즉시실행함수
  • new Function, eval → 클라이언트 단에서만 쓰면 괜츈
  • 유명함수(named function) - 함수 이름은 내부 스코프에서만 참조 가능하고 외부에서는 그 이름을 참조할 수 없고 없애지도 못해서 안전하다
  • 재귀함수 - 15,000번 이상의 재귀가 일어나면 Maximum call stack size exceeded
    • 꼬리 재귀 최적화(Tail Call Optimization)가 이뤄지지 않았음
    • 꼬리 재귀 최적화 => memoization (과거, 현재, 미래 / 3단계로 이뤄질 수 있음)

2.3 함수 실행과 인자 그리고 점 다시 보기

  • () 다시보기
    • 인자와 변수의 차이
    • 근데 함수 내에서 인자를 안 건드리는게 좋은거 아닌가?
  • this
    • 객체에 함수를 붙인 다음 그 함수를 .으로 접근하여 실행하면 함수 내부의 this가 .왼쪽의 객체가 됨 (부모가 되는거니까 그런것 아님? → . 없이 실행하면 다시 window가 this 됨)
    • 어떻게 실행됐는지가 this와 arguments를 결정한다
  • call, apply
    • null, undefined를 call의 첫 번째 인자에 넣으면 → this === window
    • call은 Function.prototype.call
    • apply, call은 동일하게 동작하지만 인자 전달 방식이 다름
      • apply는 배열이나 배열 비슷한 객체를 통해 전달
    • call 언제 쓰긴 씀???
      • Array.prototype.slice

2.4 if else || 삼항 연산자 다시보기

  • if 괄호안에서 못하는 일
    • 지역 변수 선언
    • 지역함수 선언
    • 비동기코드
  •   , &&
  • 삼항연산자

2.5 함수 실행의 괄호

  • 함수 실행을 통해 생기는 새로운 공간
    • 함수를 실행하는 괄호
      • 새로운 실행 컨텍스트가 열린다 !
      • 실행 컨텍스트 = 새롭게 열린 공간이 끝나기 전까지는 이전 공간의 상황들도 끝나지 않는다
  • 비동기 중첩 실행하기
    • 코드가 이해가 안가네… 2-80 ```js function _async(func) { return function() { arguments[arguments.length++] = function(result) { // (1) _callback(result); // (6) }; func.apply(null, arguments); // (2)

      var _callback; // (3) function _async_cb_receiver(callback) { // (4) _callback = callback; // (5) } return _async_cb_receiver; }; }

    var add = _async(function(a, b, callback) { setTimeout(function() { callback(a + b); }, 1000); });

    add(20, 30)(function(r) { // (7) console.log(r); // 50 }); ```

  • 비동기와 재귀
    • 공간을 만든다는건 알겠는데… 중첩을 왜 해야하는지??

2.6 화살표 함수

  • 화살표 함수의 최대 매력은 간결함. 이모티콘..ㅋㅋ
  • map, filter, reduce 등의 고차 함수와 함께 쓰일때 매력적