Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[박상범] 챕터 10: 일급 함수 1 #54

Merged
merged 1 commit into from
May 23, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
261 changes: 261 additions & 0 deletions 챕터_10/상범.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
# 10장 - 일급 함수 1

## 이번 장에서 살펴볼 내용

- 왜 일급 값이 좋은지
- 문법을 일급 함수로 만드는 방법
- 고차 함수로 문법을 감싸는 방법
- 일급 함수와 고차 함수로 사용한 리팩터링 두 개를 살펴보자

# 코드의 냄새: 함수 이름에 있는 암묵적 인자

함수 본문에서 사용하는 어떤 값이 함수 이름에 나타난다면 **함수 이름에 있는 암묵적 인자**는 코드의 냄새가 됨

코드의 냄새를 찾아서 일급 값으로 바꾸면 표현력이 더 좋아짐

```jsx
// as-is

// 문자열이 함수 이름에 그대로 들어있고 비슷한 구조를 가지고 있음 => 암묵적 인자 냄새남
function setPriceByName(cart, name, price) {
let item = cart(name);
// price 암묵적 인자 냄새
let newItem = objectSet(item, 'price', price);
let newCart = objectSet(cart, name, newItem);
return newCart;
}

function setQuantityByName(cart, name, quant) {
let item = cart(name);
let newItem = objectSet(item, 'quantity', quant);
let newCart = objectSet(cart, name, newItem);
return newCart;
}

function setShippingByName(cart, name, ship) {
let item = cart(name);
let newItem = objectSet(item, 'shipping', ship);
let newCart = objectSet(cart, name, newItem);
return newCart;
}
...
```

```jsx
// to-be

// 필드명을 일급 값으로 만듦
function setFieldByName(cart, name, field, value) {
// field, value로 명시적인 인자를 추가함
let item = cart(name);
let newItem = objectSet(item, field, value);
let newCart = objectSet(cart, name, newItem);
return newCart;
}

// 새로운 인자 사용
setFieldByName(cart, 'shoe', 'price', 13);
setFieldByName(cart, 'shoe', 'quantity', 3);
setFieldByName(cart, 'shoe', 'shipping', 0);
setFieldByName(cart, 'shoe', 'tax', 2.24);
```

일급값은 언어 전체에서 **어디서나 쓸 수 있다는 특징을 가지고 있음**

### **자바스크립트에서 일급이 아닌 것**

1. 수식 연산자
2. 반복문
3. 조건문
4. try/catch 블록

### **일급으로 할 수 있는 것**

1. 변수에 할당
2. 함수의 인자로 넘기기
3. 함수의 리턴값으로 받기
4. 배열이나 객체에 담기

## **객체와 배열을 너무 많이 쓰게 된다.**

장바구니와 제품처럼 일반적인 엔티티는 객체와 배열처럼 일반적인 데이터 구조를 사용해야 함

데이터를 데이터 그대로 사용하는 것의 중요한 장점은 여러 가지 방법으로 해석할 수 있다는 것이고, 이것이 데이터 지향이라고 하는 중요한 원칙임

데이터 지향은 이벤트와 엔티티에 대한 사실을 표현하기 위해 일반 데이터 구조를 사용하는 프로그래밍 형식

# **리팩터링: 암묵적 인자를 드러내기**

함수 이름에 있는 암묵적 인자를 어떻게 명시적인 함수 인자로 바꿀 수 있을까?

⇒ 암묵적 인자가 일급 값이 되도록 함수에 인자를 추가

⇒ 이렇게 하면 잠재적 중복을 없애고 코드의 목적을 더 잘 표현 가능

## **반복문 예제: 먹고 치우기**

```jsx
//준비하고 먹기
for(let i = 0; i < foods.length; i++){
let food = foods[i];
cook(food);
eat(food);
}

//설거지 하기
for(let i = 0; i < dishes.length; i++){
let dish = dishes[i];
wash(dish);
dry(dish);
putAway(dish);
}
```

## 코드를 함수화 하기

```jsx
// 준비하고 먹기
// 함수 이름에서 암묵적 인자 냄새
function cookAndEatFoods(){
for(let i = 0; i < foods.length; i++){
let food = foods[i];
cook(food);
eat(food);
}
}

cookAndEatFoods();

//설거지 하기

function cleanDishes(){
for(let i = 0; i < dishes.length; i++){
let dish = dishes[i];
wash(dish);
dry(dish);
putAway(dish);
}
}

cleanDishes();
```

## 암묵적 인자 드러내기

```jsx
//준비하고 먹기
function cookAndEatArray(array){
// 일반적인 이름의 함수명
// 명시적인 배열 인자
for(let i = 0; i < array.length; i++){
let item = array[i];
cook(item);
eat(item);
}
}

cookAndEatFoods(foods);
//인자 전달

//설거지 하기
function cleanArray(array){
// 일반적인 이름의 함수명
// 명시적인 배열 인자
for(let i = 0; i < array.length; i++){
let item = array[i];
wash(item);
dry(item);
putAway(item);
}
}

cleanArray(dishes);
//인자 전달
```

## 함수 이름에서 나는 암묵적 인자 냄새 제거하기

```jsx
//준비하고 먹기
function operateOnArray(array, func){
for(let i = 0; i < array.length; i++){
let item = array[i];
func(item);
}
}

function cookAndEat(food){
cook(food);
eat(food);
}

function clean(dish){
wash(dish);
dry(dish);
putAway(dish);
}

operateOnArray(foods, cookAndEat);
operateOnArray(dishes, clean);
```

# **리팩터링: 함수 본문을 콜백으로 바꾸기**

1) 본문과 본문의 앞부분과 뒷부분을 구분
2) 전체를 함수로 빼내기
3) 본문 부분을 빼낸 함수의 인자로 전달한 함수로 바꾸기

```jsx
try{ // 엎부분
saveUserData(user); // 본문
} catch (error) { // 뒷부분
logToSnapErrors(error);
}

try{
fetchProduct(ProductId);
} catch (error) {
logToSnapErrors(error);
}
```

## 함수로 빼내기

```jsx
function withLogging(){
try{
saveUserData(user);
} catch (error) {
logToSnapErrors(error);
}
}

withLogging(); // 함수를 만들고 호출
```

## 콜백으로 빼내기

```jsx
function withLogging(func){
try{
func() // 인자로 전달받은 함수 호출
} catch (error) {
logToSnapErrors(error);
}
}

withLogging(function(){ // 본문 전달 (인라인 정의 방법)
saveUserData(user);
});
```

## **결론 및 요약**

- 일급 값은 변수에 저장할 수 있고 인자로 전달하거나 함수의 리턴값으로 사용할 수 있다. 일급 값은 코드로 다룰 수 있는 값이다.
- 언어에는 일급이 아닌 기능이 많다. 일급이 아닌 기능은 함수로 감싸 일급으로 만들 수 있다.
- 어떤 언어는 함수를 일급 값처럼 쓸 수 있는 일급 함수가 있다. 일급 함수는 어떤 단계 이상의 함수형 프로그래밍을 하는 데 필요하다.
- 고차 함수는 다른 함수에 인자로 넘기거나 리턴값으로 받을 수 있는 함수다. 고차 함수로 다양한 동작을 추상화할 수 있다.
- **`함수 이름에 있는 암묵적 인자`**는 함수의 이름으로 구분하는 코드의 냄새다. 이 냄새는 코드로 다룰 수 없는 함수 이름 대신 일급 값인 인자로 바꾸는 **`암묵적 인자를 드러내기 리팩터링`**을 적용해서 없앨 수 있다.
- 동작을 추상화하기 위해 **`본문을 콜백으로 바꾸기 리팩터링`**을 사용할 수 있다. 서로 다른 함수의 동작 차이를 일급 함수 인자로 만든다.

⇒ 근데 회사에서 이렇게 성급한 추상화 하면 바로 리뷰 달림 ㅋㅋ
Loading