javascript 활용편 (1/3)

기본적인 javascript 활용하기

1.명령형 프로그래밍 vs 선언적 프로그래밍

명령형 프로그램은 작업 수행에 필요한 전 단계를 노출하여 흐름이나 경로를 아주 자세히 서술합니다. 반면, 선언적 프로그램, 특히 함수형 프로그램은 독립적인 블랙박스 연산들이 단순하게, 즉 최소한의 제어 구조를 통해 연결되어 추상화 수준이 높고, 정보는 한 연산에서 다른 연산으로 독립적으로 흘러가며, 분기와 반복은 상당 부분 줄이거나 아예 없애고 고수준의 추상화로 대체 합니다. 
아래의 소스코드는 선언적 프로그래밍을 이용여 짧아진 점을 강조하기 위한 소스코드이다. (점으로 연결하려면 이들 메서드가 모두 포함된 공유 객체가 있어야한다.)

2.메서드 체이닝(method chaining)

메서드 체이닝은 여러메서드를 단일 구문으로 호출하는 OOP 패턴 입니다. 

3.함수 체이닝

함수형 프로그래밍은 자료구조를 새로 만들어 어떤 요건을 충족시키는게 아니라, 배열 등의 흔한 자료구조를 이용해 다수의 굵게 나뉜 고계 연산을 적용합니다. 이러한 고계 연산으로 다음과 같은 일을 합니다.
  • 작업을 수행하기 위해 무슨 일을 해야 하는지 기술된 함수를 인수로 받는다.
  • 임시 변수의 값을 계속 바꾸면서 부수효과를 일으키는 기존 수동 루프를 대체합니다. 그 결과 관리할 코드가 줄고 에러가 날 만한 코드 역시 줄어듭니다. 

람다표현식

함수형 프로그래밍에서 탄생한 람다 표현식(lambda expression), 자바스크립트에서는 두 줄 화살표 함수(fat-arrow function)라고도 한다. 람다 표현식은 한 줄 짜리 익명 함수를 일반 함수 선언보다 단축된 구문으로 나타냅니다. 람다 함수는 여러 줄로도 표기할 수 있지만, 거의 대부분 한줄로 씁니다. 아래의 소스코드가 그 예시 입니다.
람다 표현식은 항상 어떤 값을 반환하게 만들어 함수 정의부를 확실히 함수형으로 굳힙니다. 

_.map() : 데이터를 반환

아래와 같은 소스코드를

map함수를 이용하여 간단하게 구현할 수 있다.

수학적으로 표현하면
Sx=[X1,X2,X3,...,Xn] 의 배열과 함수 F()가 있을때,
[F(X1),F(X2),F(X3),...,F(Xn)] 를 거쳐
Sy=[Y1,Y2,Y3,...,Yn] 이 나오게 된다.
즉, Sy = F(Sx)

단, map연산은 무조건 왼쪽 -> 오른쪽 방향으로 진행합니다. 오른쪽 -> 왼쪽 방향으로 진행하려면 배열 원소를 거꾸로 뒤집어야 합니다. 자바스크립트에서는 Array.reverse()에 해당하는 _.reverse()메서드를 지원합니다. reverse매소드는 배열의 값과 index들을 뒤집어 주는 함수입니다.

_.reduce() : 결과를 수집

아래와 같은 소스코드를

reduce함수를 이용하여 배열의 원하는 결과 값을 구할 수 있다. 
tip) reduce(fn, 초기값)

수학적으로 표현하면
Sx=[X1,X2,X3,...,Xn] 의 배열, 변수accum 과 함수 F()가 있을때,
결과 값 Y = F(...(F(F(F(accum,X1),X2),X3),...),Xn) 이다.

map함수와 달리 reduce함수는 누산치에 의존하기 때문에 결합법칙이 성립하지 않는 연산은 진행순서에 따라 결과가 달라집니다. 예를 들어 나눗셈이나 뺄셈 같은 연산은 결과가 완전히 달라지죠. 또 reduce는 일괄적용 연산이라서 배열을 순회하는 도중 그만두고 나머지 원소를 생략할 방법이 없습니다. 가령 어떤 입력값 리스트를 검증하는 경우, 검증 결과를 하나의 불리언 값으로 리듀스하면 입력값이 전부 올바른지 알아낼 수 있을 겁니다.
하지만 reduce는 리스트 값을 빠짐없이 방문하기 때문에 다소 비효율적입니다. 잘못된 입력값이 하나라도 발견되면 나머지 값들이 더 이상 체크할 필요가 없으니까요. 
_.some함수는 최소한 하나의 값이 올바른지 확인할때 유용하다. 원하는 조건이 나타나면 즉시반환하기 때문이다.

_.filter():원하지 않는 원소를 제거

아래와 같이 20세 이상의 사람 정보만 가져오는 기존 명령형 함수를 보자.

filter함수를 사용하여 간단하게 작성할 수 있다.

이것을 수학적으로 얘기하자면, 
원래집합의 부분집합이라 할 수 있다.

tip) 배열축약(ES7부터)
배열 축약은 map,filter의 기능을 각각 for..of 와 if 키워드를 이용하여 단축된 구문으로 캡슐화하는 함수형 장치입니다. 
예시.

4.코드 헤아리기

자바스크립트에서는 전역 이름공간을 공유하는 수천 줄의 코드를 한 페이지에 한 번에 로드할 수있습니다. 함수형 흐름은 프로그램 로직을 파헤치지 않아도 뭘 하는 프로그램인지 윤곽을 잡기 쉽기 때문에, 개발자는 코드뿐만 아니라, 결과를 내기 위해 서로 다른 단계를 드나드는 데이터의 흐름까지 더 깊이 헤아릴 수 있습니다. 

지금까지 map, reduce, filter 등의 함수를 살펴봤는데요, 이름을 잘 보면 그 어휘만으로도 함수가 데이터에 하는 일이 무엇인지 어렵잖게 추론할 수 있습니다. 그런데 관점을 조금만 틀어보면 이 함수들이 SQL구문을 쏙 빼 닮았다는 사실을 알 수 있습니다. 결국 쿼리 언어를 구사하듯 개발하는 것과 함수형 프로그래밍에서 배열에 연산을 적용하는 것은 일맥상통합니다. 

자바스크립트 믹스인
믹스인은 SQL명령어처럼 특정 형식과 연관된 함수를 부분적으로 추상한 객체입니다. 그래서 그 자체로 쓰이기 보단 다른 객체의 로직을 확장하는 용도록 활용합니다. 믹스인은 OOP시계에서 다중 상속을 지원하지 않는 언어(예를들면 javascript)에서 다중 상속을 모방하거나, 상속 등의 우회책을 쓰지 않아도 코드를 재사용 할 수 있게 합니다.


5.재귀적 사고방식

좀처럼 머릿속에 해법이 떠오르지 않는 어렵고 복잡한 문제들이 있습니다. 이럴 땐 바로 문제를 분해할 방법을 찾아야 합니다. 전체 문제를 더 작은 분신들로 쪼갤 수 있다면, 작은 문제를 하나씩 풀면서 전체 문제도 풀 수 있을 것입니다.

재귀(recursion)는 주어진 문제를 자기 반복적인 문제들로 잘게 분해한 다음, 이들을 다시 조합해 원래 문제의 정답을 찾는 기법입니다. 재귀 함수의 주된 구성 요소는 다음과 같습니다.
  • 기저 케이스(종료조건)
  • 재귀 케이스
기저 케이스는 재귀함수가 구체적인 결괏값을 바로 계산할 수 있는 입력 집합입니다. 재귀 케이스는 함수가 자신을 호출할 때 전달한 입력 집합(최초 입력 집합보다 점점 작아집니다)을 처리합니다. 

정리

  • 고계함수 map,reduce,filter를 쓰면 코드를 확장할 수 있습니다.
  • 로대시JS는 데이터 흐름과 변환 과정이 명확히 구획된 제어 체인을 통해 데이터 처리 및 프로그램 작성을 도모합니다.
  • 함수형 프로그래밍의 선언적 스타일로 개발하면 코드를 헤아리기가 쉽습니다.
  • 고수준의 추상화를 SQL어휘로 매핑하면 더 심도있게 데이터를 이해할 수 있습니다.
  • 재귀는 자기 반복적 문제를 해결하는 데 쓰이며, 정의된 자료구조를 재귀적으로 파싱해야 합니다.


출처 : 책(함수형 자바스크립트 - 루이스 아텐시오 지음)

댓글

가장 많이 본 글