[Javascript] 명령형/선언형 프로그래밍 + 함수형 프로그래밍

10tacion·2024년 4월 19일

Javascript

목록 보기
8/8
post-thumbnail

Javascript 명령형/선언형 프로그래밍 + 함수형 프로그래밍



🥷먼저 프로그래밍 패러다임에 대해서 알아보자


🎋프로그래밍 패러다임이 뭐지?

이는 프로그래밍에 대한 접근 방식 또는 코드 작성 스타일이라고 할 수 있다.

🎋대부분의 현대 프로그래밍 언어의 패러다임

명령형(절차적, OOP 등)선언형(함수형 등) 두 가지의 일반적인 패러다임으로 나뉘어진다.

일부 언어는 하나의 패러다임을 지원하도록 설계되었지만 대부분의 현대 프로그래밍 언어는 유연하게 설계되어 여러 패러다임을 지원한다. 예를 들어 JavaScript는 다양한 패러다임으로 코드를 작성하거나 이를 '다중 패러다임' 접근 방식으로 결합할 수 있는 언어이다.

아래는 프로그래밍 패러다임 종류를 계층적으로 나타낸 예시 사진이다!


🥷명령형 / 선언형 프로그래밍의 개념


🎋명령형 프로그래밍

명령형 프로그래밍은 프로그램의 상태를 변경하는 각 명령을 단계별로 지정하여 프로그램이 작업을 어떻게(HOW) 수행할것인지 방법을 설명하는 패러다임이다. ex) Smalltalk, C ,COBOL

  • 어떻게(HOW) 할 것인지에 초점을 두고 코드를 작성하는것!

🎋선언형 프로그래밍

선언형 프로그래밍은 제어 흐름을 명시적으로 지정하지 않고 프로그램이 무엇(WHAT)을 할것인지를 표현하는 패러다임이다. ex) Enlang, Haskell, Loglan

  • 무엇(WHAT) 을 할 것 인지 초점을 두고 코드를 작성한다고 생각하면 쉽다.

즉, 선언적 프로그래밍은 개발자로 하여금 구현 세부사항에서 벗어나 결과에 집중할 수 있게 해준다

물론 결국에는 모든 것이 CPU에 대한 명령으로 컴파일된다. 따라서 어떤 면에서 선언적 프로그래밍은 명령형 프로그래밍 위에 있는 추상화 계층이라고 할 수 있다

🎋간단 예시 청소시키기

청소 시킬 때

선언형 방식
야 내 방 좀 깨끗하게 해줘

명령형 방식
야 내 방 주방을 클리너로 닦고나서, 바닥 청소기로 돌린 후에 걸레로 깨끗하게 닦고, 환기 30분 정도 시켜줘


🎋간단 예시 코드

숫자를 2배하여 배열에 저장하는 작업을 수행한다고 했을 때, 명령형 / 선언형 예시 코드이다

//명령형 어떻게(HOW) 할건데
const doubleMapImperative = numbers => {
  const doubled = [];
  for ( let 1 = 0 ; i < numbers.length ; i++) {
    doubled.push(numbers[i] * 2);
  }
  return doubled;
}

//선언형 무엇을(WHAT) 할건데
const doubleMapDeclarative = numbers => numbers.map(n => n * 2);

🥷함수형 프로그래밍


함수형 프로그래밍은 선언형 프로그래밍에 속하며 상태와 데이터를 변경하지 않고 표현식과 함수를 사용하여 프로그램을 구축하는 패러다임이다. 함수형 프로그래밍은 직관적이고 버그에 강한 코드를 작성하는 것을 목표로 한다.

그래서 구체적으로 함수형 프로그래밍이란 뭔지 알아보자

🎋함수형 프로그래밍이란

함수형 프로그래밍은 다음 3가지 조건을 만족해야한다.

  • 원형의 값을 변형하지 않는다
  • 순수 함수 사용: 고정 입력값에 대한 고정 출력
  • 표현식 및 선언 사용

표현식 및 선언 사용은 당연한 부분이다. 위의 2가지 조건에 대해 차근차근 알아보자


🎋조건 1: 원형의 값을 변경하지 않는다

immutable vs mutable

자바스크립트에서는 불변성을 유지하는 값(immutable)들과 그렇지 않은 값(mutable)들이 나누어져 있다.

mutableimmutable
생성된 이후 수정 가능생성된 이후 수정 불가능
이미 존재하는 객체에 재할당(값 변경)새로운 객체를 생성하여 재할당
참조타입원시타입
pass by referencepass by value

mutable: Object Array..
immutable: Boolean, Number, String, null, undefined, Symbol ..


pass by value & pass by reference

📌 pass by value
원시 타입(immutable)은 pass by value 라는 방식을 사용한다.

let score = 80;
let copy = score;

copy = 30
score; // 80

값에 의한 전달 이라는 말처럼 copy에는 score가 저장하고 있던 80이 복사되어 저장된다. 따라서 copy의 값을 변경해도 score에는 아무 영향이 없다.

📌 pass by reference
참조 타입(mutable)은 pass by reference 라는 방식을 사용한다.

let score = [10,20,30];
let copy = score;

copt[0] = 30;

score; // [30,20,30]

값이 아니라 메모리 주소를 저장하고 전달한다. 따라서 copy에는 score의 메모리 주소 자체가 전달되어 copy의 값을 바꾸면 score에 값까지 같이 바뀌게 된다

➡️ 이 때문에 mutable 방식에서는 값을 수정할 때 주의 해야한다.

그렇다면 불변성이 뭘까?

자바스크립트에서 불변성이란 객체가 생성된 이후 그 상태를 변경할 수 없는 것을 의미한다
여기서 상태를 변경할 수 있는 것과 값을 재할당하는 것은 다르다는 것을 알아야한다.

상태가 필요할 때는 원본 데이터를 변경하지 않고 새로운 데이터를 생성하여 재할당 후 사용한다.

immutable

let a = 1;  
a = 2; // 2를 생성하여 재할당 이 때 1은 메모리에 남아 있음 ( 1이 생성되고 상태가 변경되지 않음 )

mutable

let sopt = ['wb','ob','pt'];
sopt[0] = 'ob'; // sopt[0]의 값 자체를 바꾼 것 -> 불변성 만족하지 않음
sopt;
// => result ['ob','ob','pt']

원형의 값을 변경하지 않으려면?

결국 불변성을 지켜야한다는 말이다! immutable은 불변성 유지하지만, mutable배열 같은 경우는 우리가 마음대로 존재하는 객체에 값을 재할당 할 수 있다 즉 원형의 값을 변경할 수 있다. 이러한 상황을 피해야한다.

원형의 값을 변형 하는 경우

var rooms = ['H1','H2','H3'];
rooms[2] = 'H4';
romms;
// => result ['H1','H2','H4']

원형의 값을 변경하지 않는 경우

const rooms = ['H1','H2','H3'];
const newRooms = rooms.map(function (rm) {
	if (rm === 'H3') return 'H4'
  	else return rm;
});
newRooms; // => ['H1','H2','H4']
rooms; // => ['H1','H2','H3']

결국 원형의 값을 변경하지 않으려면 값만을 복사해서 새로운 객체에 할당하는 방식으로 써야한다!
이러한 조건을 만족하는것이 함수형 프로그래밍의 첫번째 조건이었다.


🎋조건 2: 순수 함수 사용

먼저 순수함수가 무엇인지 알아야한다

순수 함수는 동일한 입력값에 대한 동일한 값을 반환하며 외부 상태에 의존하지 않는 함수이다. 이 때문에 순수 함수는 side effect를 일으키지 않는다.

그렇다면 구체적으로 순수함수의 특징을 정리해보자

  • 동일한 인수가 전달되면 언제나 동일한 값을 반환한다.
  • 어떠한 외부상태에도 의존하지 않고 오직 매개변수를 통해 함수내부로 전달된 인수에게만 의존해 값을 생성하여 반환한다.
  • 일반적으로 최소 하나 이상의 인수를 전달받는다.
  • 함수의 인수를 변경하지 않는것이 기본이다. 즉, 순수함수는 인수의 불변성을 유지한다.

순수함수의 예시 코드

순수 함수

let count = 0;

fucntion increase(n) {
  return n+1; // 오직 매개변수를 통해 전달된 인수에게만 의존한다.
}

비순수 함수

let count = 0;

fucntion getId() {
  return count++; // 외부 상태에 의존한다. (외부 상태의 값이 의도치 않게 달라지면 side effect 발생!)
}


위 예시 처럼 비순수 함수는 사이드이펙트가 생길 수 있으므로 주의해야한다.

함수형 프로그래밍에서 순수 함수 사용

이러한 side effect를 방지하기 위해서 함수형 프로그래밍에서는 순수 함수만 사용한다.

+ js 자체적으로 제공하는 순수함수(메서드)

filter map reduce concat Object.assign ...

이 함수들은 모두 값을 변경하지 않고 새로운 객체를 만들어서 사용한다! 함수형 프로그래밍에 사용하면 굿

이제 우리도 함수형 프로그래밍을 바탕으로 코드를 작성해보자


🥷우리는 어떤 방식을 지향해야하는가?


🎋FE가 대부분 함수형 프로그래밍을 지향하는 이유

  1. js는 처음부터 함수형 프로그래밍을 지향했다
    자바스크립트를 처음 만들 때부터 창시자는 자바스크립트를 함수형 언어로 만들고 싶어했다.
    그래서 내부 메커니즘함수형 프로그래밍을 기초로 만들어지게 되었는데 클로저, 익명함수와 같은 개념들이 이에 해당한다. 이러한 함수형 체계들은 javascript의 DOM을 처리하거나 이벤트 핸들러를 지정하는 부분들을 굉장히 간소화하는데 큰 역할을 한다.

  2. 함수형 프로그래밍은 Javascript의 번들크기를 줄이는데 용이하다.
    javascript는 스크립트 언어기 때문에 스크립트의 길이가 곧 파일의 크기이며 내려받아서 실행을 시켜야 하는 만큼 코드의 크기는 작을수록 좋다. js 언어 구조상 함수형 프로그래밍이 이 코드의 크기를 줄이는데 좋다고한다.

  3. 개발자들은 this를 쓰지 않는 방향으로 진화했다
    자바스크립트의 this는 예전부터 문법적으로 불편한 존재였다. function의 scope마다 this가 만들어지고 this는 호출한 객체로 취급되는 동적바인딩이라는 개념은 생소했고, 특히 Arrow Function이 만들어지기 전에는 외부에 있는 this를 이벤트 핸들러에서 사용하기 위해서 클로저를 이용해서 작성을 하는 기법들은 대단히 불편한 부분이었다.
    이런 기능을 보완하고자 ES6에서는 Arrow Function이 만들어지긴 했지만, 개발자들은 불편한 this을 쓰지 않는 방향으로 진화했다.

  4. js의 핵심 API는 함수형 매커니즘을 기반으로한다.
    javascript를 다루다 보면 Array를 다루기 위한 map, filter, reduce 나 비동기를 다루기 위한 Promise의 then, 그리고 이벤트를 다루기 위한 Element의 addEventListener 등의 핵심 API들이 모두 함수형 매커니즘을 기반으로 하고 있다.

🎋결론

결국 FE개발자는 javascript를 쓸 수 밖에 없는데 이 javascript가 함수형 프로그래밍을 하면 더 유리하도록 만들어져 있다. 따라서 함수형 프로그래밍에 대한 이해를 하게 되면 우리는 javascript를 더 잘 쓸 수 있을것이다. 물론 정답은 없다!

profile
늦게 자고 일찍 일어나기

0개의 댓글