React - 함수형 프로그래밍

milkbottle·2023년 12월 10일
0

React

목록 보기
3/33

함수형이란

자바스크립트에서는 함수를 변수처럼 취급할 수 있다. 아래의 예제를 보면 이해하기 쉬울 것이다.

변수로 저장하여 호출하는 예제

var log = function(message) {
  console.log(message);
};

log("변수를 함수처럼!");

// 변수를 함수처럼!

위는 함수를 log라는 변수에 저장하여 이 변수의 이름명에 괄호를 넣어 호출을 할 수 있다.

함수를 다른 함수의 인자로 사용하는 예제

const insideFn = logger => {
  logger("함수를 다른 함수의 인자로 사용!");
};

insideFn(message => console.log(message));
// 함수를 다른 함수의 인자로 사용!

이해하기 어려울 수도 있다. 설명을 하자면, insideFn은 함수이다.

어떠한 함수나하면, 함수를 인자로 가지는 함수이다.

풀어서 다른 표현으로 이해해보자.

const insideFn = function (logger) {
  logger("함수를 다른 함수의 인자로 사용!");
};

logger라는 인자를 받는데, 이는 함수이다.

logger 함수에 파라미터로 함수를 다른 함수의 인자로 사용!이라는 String 형태의 값을 사용한다.

이 insideFn에서 logger인 인자로 message => console.log(message)라는 함수를 사용한 것이다.

함수에서 함수를 반환하는 예제

const createScream = function(logger) {
  retrun function(message) {
    logger(message.toUpperCase() + "!!!");
  };
};

const scream = createScream(message => console.log(message));

scream('함수가 함수를 반환!');
// 함수가 함수를 반환!

함수를 인자로 사용하는 함수를 반환하는 것이다.

말이 어려워보이지만, 책에서 이해시키려고한 예제이니, 이해만 됐다면 상관없다고 생각한다.

명령형과 선언형이란?

명령형 프로그래밍

const string = "Replace to hyphen";
const result = "";

for(var i=0; i<string.length; i++) {
  if(string[i] === " ") {
    result += "-";
  } else {
  	result += string[i];
  }
}

console.log(result);
// Replace-to-hyphen

코드로 원하는 결과를 달성해 나가는 과정에만 관심을 두는 프로그래밍 스타일이다.

해당 과정에 대한 코드가 모두 담겨있지만,

이게 어떻게 구현되어있는지 이해하려면 설명이나 주석이 필요할 수가 있다.

선언형 프로그래밍

const string = "Replace to hyphen";
const result = string.replace(/ /g, "-");

console.log(result);

string.replace라는 함수와 정규표현식을 사용해서 모든 공백을 하이픈으로 바꾸었다.

replace함수로 글자를 대치하는 기능을, 정규표현식으로 공백을 감지하는 기능을 추상적으로 사용한다.

즉, 선언적 프로그래밍이란 추상적으로 설계한 코드를 사용하는 것이고,

우리가 모르는 구현과정이 추상화를 통해 감춰진 것이다.

함수형 프로그래밍의 개념

불변성

let movie = {
  title = "서울의 봄",
  genre = "역사",
  rating = 0,
}

영화에 대한 값을 저장하는 객체가 있다고 가정하자.

let movie = {
  title = "서울의 봄",
  genre = "역사",
  rating = 0,
}

function rateMovie(movie, rating) {
  movie.rating = rating;
  return movie;
}

console.log(rateMovie(movie, 5).rating)); // 5
console.log(movie.rating); // 5

영화에 평점을 메기는 함수가 있다. 이 함수는 넘겨받은 movie 객체의 rating을 변경한다.

자바스크립트에서 함수의 인자는 call by reference 이다. 복사본이 아니라, 실제 그 값을 변경해버린다.

그래서 console.log로 함수의 결과와, 기존의 movie 객체의 rating 값을 보면 5로 반영이 된 것을 볼 수 있다.

let movie = {
  title = "서울의 봄",
  genre = "역사",
  rating = 0,
}

function rateMovie(movie, rating) {
  return Object.assign({}, movie, {rating:rating});
};

console.log(rateMovie(movie, 5).rating)); // 5
console.log(movie.rating); // 0

Object.assign을 통해 새로운 movie 객체를 복사하여 변경하였기 때문에 다른 결과가 나온다.

c언어에서는 &, * 없이 함수의 인자를 사용하면 call by value로 아예 다른 변수로 취급하게 되는데,

이를 사용하여 이와 비슷한 효과를 볼 수 있다.

const rateMovie = (movie, rating) => ({
  ...movie,
  rating
});

위는 화살표 함수와 객체 스프레드 연산자를 통해 같은 기능의 객체 복사 변경을 구현한 것이다.

Array.push() vs Array.concat()

const a = ["lion", "tiger"];
const b = a;
b.push("cat", "dog");
console.log(a); // ["lion", "tiger", "cat", "dog"]
console.log(b); // ["lion", "tiger", "cat", "dog"]
console.log(Object.is(a, b)); //

push는 배열에 원소를 추가하며 길이를 반환한다.

const a = ["lion", "tiger"];
const b = aa.concat("cat", "dog");
console.log(a); // ["lion", "tiger"]
console.log(b); // ["lion", "tiger", "cat", "dog"]
console.log(Object.is(a, b)); // false

concat은 배열에 원소를 추가한 새로운 배열을 반환한다.

concat함수를 통해 불변성을 지키며 배열에 값을 추가할 수 있다는 말이다.

순수 함수

순수 함수는 인자에 의해서만 반환값이 결정되는 함수를 뜻한다.

그 말은 하나 이상의 인수가 있고, 인자가 같다면 항상 같은 값이나 함수를 반환한다는 말도 된다.

순수하지 않은 함수

var num = 0;
function add(a, b) {
  return num+a+b;
}

console.log(add(1,2)); // 3
num = 2;
console.log(add(1,2)); // 5

함수의 인자로 a, b를 가지지만 반환값은 num이라는 친구에게도 종속되어 있다.

그래서 같은 인자인데도 불구하고, 반환값이 달라진다. 이는 순수하지 않은 함수라고 한다.

순수 함수

function add(a, b) {
  return a+b;
}

console.log(add(1,2)); // 3
console.log(add(1,2)); // 3
console.log(add(3,5)); // 8

딱봐도 간단해 보인다. 간단해서 순수하다고 하는건가..

아무튼, 인자가 같으면 같은 값을 반환하고, 반환 수식 자체도 인자에만 종속되어 있으므로 순수 함수이다.

데이터 변환

불변성을 통해 기존의 데이터를 변경하지않고, 데이터를 복사하여 이를 변환할 수 있다.

실제 Javascript 함수에도 이러한 기능을 하는 함수들이 많다.

대표적으로 map, reduce, filter가 있다.

이 함수들은 Iterable한 배열을 대상으로 순회를 하여, 각 원소마다 인자로 받은 함수를 실행하며 변경한다.

Array.filter()

const numbers = [1, 2, 3, 4, 5];

// 짝수만 필터링
const evenNumbers = numbers.filter((num) => num % 2 === 0);

console.log(evenNumbers); // [2, 4]

numbers 배열을 순회를 하여, 각 원소를 num이라 칭하고, num이 2로 나누어 떨어지는 값만 저장한다.

Array.map()

const numbers = [1, 2, 3, 4, 5];

// 각 숫자를 제곱하여 새로운 배열 생성
const squaredNumbers = numbers.map((num) => num ** 2);

console.log(squaredNumbers); // [1, 4, 9, 16, 25]

모든 원소를 순회하여, 각 원소를 num이라 칭하고, num을 주어진 식으로 값을 변경하여 저장한다.

Array.reduce()

const numbers = [1, 2, 3, 4, 5];

// 모든 숫자를 더한 결과 계산
const sum = numbers.reduce((accumulator, current) => accumulator + current, 0);

console.log(sum); // 15

reduce의 인자 함수는 2개의 인자를 가진다.

첫 번째 인자는 임시적인 변수이며, 두 번째 인자는 filter, map에서 본 num같은 원소의 값 저장하는 변수이다.

그리고 reduce는 인자가 2개인데 첫 번째 인자는 함수이고, 두 번째 인자는 전 줄의 임시적인 변수를 초기화하는 역할을 한다.

여기서는 accumulator(누적값)을 0으로 초기화하여서, 배열을 순회하며 각 원소를 current라 칭하고 값을 누적시킨다고 볼 수 있다.

그리고 인자 함수의 반환 값은 새로 임시적인 변수인 accumulator를 초기화한다.

0개의 댓글