본문 바로가기
책정리/자바스크립트

함수형 자바스크립트 - 1장 함수형 자바스크립트 소개

by 난파선 2017. 1. 9.


1.1 자바스크립트 활용사례

자바스크립트를 사용하는 이유

  • 풍부한 접근성
  • 보편성
  • 이식성
  • 단일 페이지 애플리케이션 패러다임의 훌륭한 본보기다.
  • 자바스크립트가 함수형 프로그래밍을 지원한다.
  • 계속 발전하고 있는 언어이다.
[1,2,3].forEach(console.log);   // 배열의 요소를 한 개씩 함수로 전달한다.

apply 함수

  • 배열 요소를 함수의 인자처럼 전달한다.
function splat(fun) {
  return function(array) {
    return fun.apply(null, array);
  };
}

var addArrayElements = splat(function(x, y) { return x + y });

addArrayElements([1, 2]);    //배열을 전달
//-> 3
  • 함수에는 인자의 개수와 형식에 제한이 없다.
  • 함수는 arguments라는 지역 변수를 액세스할 수 있는 데 arguments는 함수의 인자로 제공된 값을 저장하는 배열과 유사한 변수이다.

call 함수

  • 요소 한 개씩 인자로 받는 다.
function unsplat(fun) {
  return function() {
    return fun.call(null, _.toArray(arguments));
  };
}

var joinElements = unsplat(function(array) { return array.join(' ') });

joinElements(1, 2);
//-> "1 2"

1.1.1 자바스크립트의 몇 가지 한계

  • 표현의 명확성과 관련한 문제가 있다.
  • 명령형 기법, 지역 스코핑 의존은 기본적으로 안전하지 않은 특성이다.
  • 변동성이 큰 프로그램에서는 프로그램이 커질수록 혼동이 생길 가능성이 크다.
  • 언어의 이상한점, 안전하지 않는 특성, 수많은 경쟁 라이브러리

1.2 함수형 프로그래밍 시작하기

함수형 프로그래밍은 값을 추상화의 단위로 바꾸는 기능을 하며 결국 바뀐 값들로 소프트웨어 시스템이 만들어진다.

1.2.1 함수형 프로그래밍이 중요한 이유

p.28

마이클 페더스 - 객체지향 프로그래밍은 움직이는 부분을 캡슐화하여 코드 이해를 돕고, 함수형 프로그래밍은 움직이는 부분을 최소화하여 코드 이해를 돕는다.

  • 객체 지향에서는 문제를 '명사'나 객체의 집합으로 나누는 반면 함수형에서는 같은 문제를 '동사'나 함수의 그룹으로 나눈다.
  • 객체 지향 스타일을 엄격하게 준수하는 시스템에서는 객체 간의 상호 작용이 발생하면 각 객체의 내부 값이 바뀌면서 전체 시스템의 상태가 바뀐다.
  • 함수형 프로그래밍에서는 관찰할 수 있는 상태(캡슐화, 스코핑, 스레드) 변화를 최소화하려고 애쓴다.
  • 새로운 기능을 추가할 때는 새로운 함수가 지역화되고 비파괴적인 데이터 전이 과정에서 어떻게 동작할 것인지를 파악하는 것이 핵심이다.
  • 함수형 프로그래밍에서는 시스템을 만들 때 명령행을 이용하여 모듈성을 높을 수 있도록 가능한 한 명시적 상태 변화를 최소한으로 유지한다.

1.2.2 함수 - 추상화 단위

버틀러 램슨 - 실행할 수 있고, 올바로 동작하며, 빨리 실행되도록 만들어라.

테스트 주도 개발 - 실행할 수 있게 한 다음, 올바로 동작하게 하고, 그 다음 빠르게 실행되도록 만들어라.

한 함수에서 동작과 에러를 처리하는 방식

function parseAge(age) {
  if (!_.isString(age)) throw new Error("Expecting a string");    // 문자열이 아닐 경우 에러 처리
  var a;

  console.log("Attempting to parse an age");    // 함수에 대한 정보 출력

  a = parseInt(age, 10);

  if (_.isNaN(a)) {    // 숫자가 아닐 경우 경고출력
    console.log(["Could not parse age:", age].join(' '));
    a = 0;
  }

  return a;
}

에러, 정보, 경고를 추상화한 코드

function fail(thing) {
  throw new Error(thing);
}

function warn(thing) {
  console.log(["WARNING:", thing].join(' '));
}

function note(thing) {
  console.log(["NOTE:", thing].join(' '));
}

function parseAge(age) {
  if (!_.isString(age)) fail("Expecting a string");
  var a;

  note("Attempting to parse an age");
  a = parseInt(age, 10);

  if (_.isNaN(a)) {
    warn(["Could not parse age:", age].join(' '));
    a = 0;
  }

  return a;
}
  • 출력 기능을 수정하기 쉬워졌다.

1.2.3 캡슐화와 은닉

  • 자바스크립트는 데이터 은닉을 직접적으로 제공하지 않으므로 클로저라는 것을 이용해서 데이터를 감춘다. 3장에서 자세히

1.2.4 함수 - 동작 단위

기본적인 인덱스를 이용한 배열 값 접근

  • 자바스크립트의 핵심 동작이므로 따로 함수로 만들지 않으면 동작을 고칠 수 없다.
var letters = ['a', 'b', 'c'];

letters[1];
//-> 'b'

함수로 구현한 배열 인덱싱

  • 배열 인덱싱 동작을 추상화 했다.
function naiveNth(a, index) {
  return a[index];  // a라는 배열과 index를 받아 배열 값 리턴
}

개선된 배열 인덱싱 함수

  • index가 숫자가 아닌 데이터 일 경우 처리
  • a가 배열 혹은 문자열이 아닐 경우를 확인하는 추상화 함수
  • index가 0미만, 배열 길이 보다 큰 인덱스일 경우 처리
function isIndexed(data) {
  return _.isArray(data) || _.isString(data);
}

function nth(a, index) {
  if (!_.isNumber(index)) fail("Expected a number as the index");
  if (!isIndexed(a)) fail("Not supported on non-indexed type");
  if ((index < 0) || (index > a.length - 1))
    fail("Index value is out of bounds");

  return a[index];
}

추상화된 배열 인덱싱 함수로 만든 또다른 추상화 함수

function second(a) {    //a 라는 배열의 두번째 값을 리턴한다.
  return nth(a, 1);
}

1.2.5 데이터 추상화

  • 객체지향은 프로토타입이나 클로저 특성을 이용하여 클래스 기반 프로그램을 만든 다.
  • 함수형 프로그래밍에서는 배열과 객체의 처리에 중점을 둔다.

CSV 파일을 처리하는 프로그램

  • 함수형 프로그래밍에서는 하나의 데이터를 다른 형태의 데이터로 변환하는 것이 핵심이다.
  • _.reduce : 배열과 함수,초기값을 받아 순서대로 값 넣고 나온 리턴 값과 그 다음 값을 함수에 넣어 연속으로 처리한다.
  • _.map : 배열과 함수를 입력 받아 배열에 있는 값 각각에 함수를 적용한다.
  • _.rest : 배열의 첫번째 값을 뺀 배열 리턴
  • _.first : 배열의 첫번째 값 리턴
function lameCSV(str) {
  return _.reduce(str.split("\n"), function(table, row) {    /
    table.push(_.map(row.split(","), function(c) { return c.trim()}));
    return table;
  }, []);
};

var peopleTable = lameCSV("name,age,hair\nMerble,35,red\nBob,64,blonde");

peopleTable;
//-> [["name",  "age",  "hair"],
//    ["Merble", "35",  "red"],
//    ["Bob",    "64",  "blonde"]]

좀 더 구체적인 데이터 추상화

function selectNames(table) {
  return _.rest(_.map(table, _.first));
}

function selectAges(table) {
  return _.rest(_.map(table, second));
}

function selectHairColor(table) {
  return _.rest(_.map(table, function(row) {
    return nth(row, 2);
  }));
}

var mergeResults = _.zip;
  • 일반적인 컬렉션 처리 함수와 관련된 함수형 접근 방식은 사람 자체와 관련된 데이터를 처리하는 데 효율적인 반면 사람을 시뮬레이션하는 작업에는 객체 지향이 더 적합하다.
  • '간단한 데이터를 조작하는 함수'라는 제한을 두었더니 프로그램이 유연해 졌다.

1.2.6 함수형 자바스크립트 맛보기

null 또는 undefined 여부 검사, 참인지 여부를 결정하는 함수

function existy(x) { return x != null };

function truthy(x) { return (x !== false) && existy(x) };


function doWhen(cond, action) {
  if(truthy(cond))
    return action();
  else
    return undefined;
}

function executeIfHasField(target, name) {
  return doWhen(existy(target[name]), function() {
    var result = _.result(target, name);
    console.log(['The result is', result].join(' '));
    return result;
  });
}
  • 함수 형태로 '존재'의 추상화를 정의한다.
  • 기존 함수를 이용해서 '참거짓'의 추상화를 정의한다.
  • 위 함수를 다른 함수의 파라미터로 제공해서 어떤 동작을 하도록 한다.


댓글