Curring ์ปค๋ง

radaยท2025๋…„ 3์›” 30์ผ
0

๊ฐœ๋ฐœ

๋ชฉ๋ก ๋ณด๊ธฐ
25/43

๐Ÿ  Curring

์ˆ˜ํ•™๊ณผ ์ปดํ“จํ„ฐ ๊ณผํ•™์—์„œ ์ปค๋ง์ด๋ž€ ๋‹ค์ค‘ ์ธ์ˆ˜ ์„ ๊ฐ–๋Š” ํ•จ์ˆ˜๋ฅผ ๋‹จ์ผ ์ธ์ˆ˜๋ฅผ ๊ฐ–๋Š” ํ•จ์ˆ˜๋“ค์˜ ํ•จ์ˆ˜์—ด๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค. ๋ชจ์ง€์ฆˆ ์‡คํ•‘ํด์— ์˜ํ•ด ๋„์ž…๋˜์—ˆ๊ณ , ์ดํ›„ ํ•˜์Šค์ผˆ ์ปค๋ฆฌ์— ์˜ํ•ด ๋ฐœ์ „ํ•˜์˜€๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์„ธ ๊ฐœ์˜ ์ธ์ˆ˜๋ฅผ ๊ฐ€์ง€๋Š” ํ•จ์ˆ˜๋ฅผ ์ปค๋งํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์„ธ ๊ฐœ์˜ ํ•จ์ˆ˜๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค.

์ปค๋ง์€ ํŠœํ”Œ(tuple)์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ธ์ˆ˜๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š” ํ•จ์ˆ˜๋ฅผ, ๋‹จ ํ•˜๋‚˜์˜ ์ธ์ˆ˜๋งŒ ๋ฐ›๊ณ  ๋‚˜๋จธ์ง€ ํŠœํ”Œ์—์„œ ์›๋ž˜ ํ•จ์ˆ˜๊ฐ€ ๋ฐ›์„ ์ถ”๊ฐ€ ์ธ์ˆ˜๋ฅผ ํ•˜๋‚˜์”ฉ ๋ฐ›๋Š” ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํ”„๋กœ์„ธ์Šค์ž…๋‹ˆ๋‹ค.

๐ŸŒˆ ์ผ๋ฐ˜์ ์ธ ์ปค๋ง

// ์ปค๋ง ๋ณ€ํ™˜์„ ํ•˜๋Š” curry(f) ํ•จ์ˆ˜ (์ผ๋ฐ˜ํ•จ์ˆ˜ ver1)
function curry(f) {
  return function(a) {
    return function(b) {
      return f(a, b);
    };
  };
}

// ์ปค๋ง ๋ณ€ํ™˜์„ ํ•˜๋Š” curry(f) ํ•จ์ˆ˜ (ํ™”์‚ดํ‘œํ•จ์ˆ˜ ver)
const curry = f => a => b => f(a, b);

// f์— ์ „๋‹ฌ๋œ ํ•จ์ˆ˜
const sum = (a, b) => a + b;

const curriedSum = curry(sum);

console.log(curriedSum(1)(2)); // 3


// ์ปค๋ง ๋ณ€ํ™˜์„ ํ•˜๋Š” curry(f) ํ•จ์ˆ˜ (์ผ๋ฐ˜ํ•จ์ˆ˜ ver2)
function curryLog(date) {
  return function(level) {
    return function(message) {
      console.log(`[${date.toLocaleTimeString()}] [${level}] ${message}`);
    };
  };
}
const now = new Date();
const logNow = curryLog(now);
const logError = logNow('ERROR');
const logWarning = logNow('WARNING');

logError('์„œ๋ฒ„ ์—ฐ๊ฒฐ ์‹คํŒจ');
logWarning('๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๋†’์Œ');

์˜ˆ์ œ 1์˜ ํ•จ์ˆ˜๋Š” ๋‹ค์Œ์˜ ์ˆœ์„œ๋กœ ๋™์ž‘ ๋ฉ๋‹ˆ๋‹ค.

  • curry(func)์˜ ๋ฐ˜ํ™˜ ๊ฐ’์€ function(a) ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค.
  • curriedSum(1) ๊ณผ ๊ฐ™์€ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ์„ ๋•Œ, 1์€ ๋ ‰์‹œ์ปฌ ํ™˜๊ฒฝ์— ์ €์žฅ์ด ๋˜๊ณ  function(b)๊ฐ€ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.
  • ๋ฐ˜ํ™˜๋œ function(b) ํ•จ์ˆ˜๊ฐ€ 2๋ฅผ ์ธ์ˆ˜๋กœ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜ ๊ฐ’์ด ์›๋ž˜์˜ sum์œผ๋กœ ๋„˜๊ฒจ์ ธ์„œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
  • ์ตœ์ข…์ ์œผ๋กœ sum(1, 2) ๊ฐ€ ํ˜ธ์ถœ๋˜์–ด 1 + 2์ธ 3์ด ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.

๐ŸŒธ ์ปค๋ง์˜ ์žฅ์ 

  • ํŠน์ˆ˜ํ™”: ์ผ๋ฐ˜์ ์ธ ํ•จ์ˆ˜๋กœ๋ถ€ํ„ฐ ํŠน์ˆ˜ํ™”๋œ ํ•จ์ˆ˜ ์ƒ์„ฑ ๊ฐ€๋Šฅ
  • ์กฐํ•ฉ์„ฑ: ํ•จ์ˆ˜ ์กฐํ•ฉ์ด ๋” ์‰ฌ์›Œ์ง
  • ๋ถ€๋ถ„ ์ ์šฉ: ์ผ๋ถ€ ์ธ์ž๋Š” ์ง€๊ธˆ, ๋‚˜๋จธ์ง€๋Š” ๋‚˜์ค‘์— ์ ์šฉ ๊ฐ€๋Šฅ
  • ๊ฐ€๋…์„ฑ: ์ฝ”๋“œ๋ฅผ ๋” ์„ ์–ธ์ ์œผ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Œ

์ปค๋ง์€ ์ผ๋ถ€ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฏธ๋ฆฌ ์„ค์ •ํ•˜์—ฌ ํ•จ์ˆ˜์˜ ๋ณ€ํ˜•์„ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ ํŠนํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.


## ๐ŸŒˆ ๊ฐ์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ปค๋ง

๐ŸŒธ ์ปค๋ง์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ

const todos = [
  { id: 3, content: 'HTML', completed: false },
  { id: 2, content: 'CSS', completed: true },
  { id: 1, content: 'Javascript', completed: false }
];

const getTodosIdArr = todos => todos.map(todo => todo.id);
const getTodosContentArr = todos => todos.map(todo => todo.content);
const getTodosCompletedArr = todos => todos.map(todo => todo.completed);

console.log(getTodosIdArr(todos)); // [ 3, 2, 1 ]
console.log(getTodosContentArr(todos)); // [ 'HTML', 'CSS', 'Javascript' ]
console.log(getTodosCompletedArr(todos)); // [ false, true, false ]

์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ์œ„์™€ ๊ฐ™์ด ์ž‘์„ฑํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ์ปค๋ง์„ ์ ์šฉํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐ŸŒธ ์ปค๋ง ์‚ฌ์šฉ ํ›„

const todos = [
  { id: 3, content: 'HTML', completed: false },
  { id: 2, content: 'CSS', completed: true },
  { id: 1, content: 'Javascript', completed: false }
];

const get = property => object => object[property];

const getId = get('id');
const getContent = get('content');
const getCompleted = get('completed');

const getTodosIdArr = todos => todos.map(getId);
const getTodosContentArr = todos => todos.map(getContent);
const getTodosCompletedArr = todos => todos.map(getCompleted);

console.log(getTodosIdArr(todos)); // [ 3, 2, 1 ]
console.log(getTodosContentArr(todos)); // [ 'HTML', 'CSS', 'Javascript' ]
console.log(getTodosCompletedArr(todos)); // [ false, true, false ]

์ปค๋ง์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ธ์ž์˜ ์ˆœ์„œ๋Š” ์ค‘์š”ํ•œ๋ฐ, ์•ž์— ์กด์žฌํ•˜๋Š” ์ธ์ž์ผ ์ˆ˜๋ก ๋ณ€๋™๊ฐ€๋Šฅ์„ฑ์ด ์ ๊ณ  ๋’ค์— ์žˆ๋Š” ์ธ์ž์ผ ์ˆ˜๋ก ๋ณ€๋™๊ฐ€๋Šฅ์„ฑ์ด ๋†’๊ธฐ ๋•Œ๋ฌธ์— ์ด ์ˆœ์„œ๋ฅผ ๊ณ ๋ คํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์„ค๊ณ„ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

๐ŸŒธ ์ปค๋ง์˜ ํ™œ์šฉ

์ •๋ณด๋ฅผ ํ˜•์‹ํ™”ํ•˜๊ณ  ์ถœ๋ ฅํ•˜๋Š” ๋กœ๊ทธํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ , ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜๋Š” ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๋งŽ์€ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

function log(date, importance, message) {
  alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}

lodash๋ฅผ ์ด์šฉํ•œ ์ปค๋ง

log = _.curry(log);


log(new Date(), "DEBUG", "some debug"); // log(a, b, c)
log(new Date())("DEBUG")("some debug"); // log(a)(b)(c)

์ด ๊ฒฝ์šฐ ๋‘˜๋‹ค ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™์ด ๋ฉ๋‹ˆ๋‹ค.

์ด ์ดํ›„ ์•„๋ž˜์ฒ˜๋Ÿผ ํ˜„์žฌ ์‹œ๊ฐ„์œผ๋กœ ๋กœ๊ทธ๋ฅผ ์ถœ๋ ฅํ•˜๋Š”๋ฐ ํŽธ๋ฆฌํ•˜๋„๋ก logํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

// logNow๋Š” log์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ˆ˜๊ฐ€ ๊ณ ์ •๋œ partial
const logNow = log(new Date());

logNow("INFO", "message"); // [HH:mm] INFO message

const debugNow = logNow("DEBUG");

debugNow("message"); // [HH:mm] DEBUG message

์ตœ์ข…์ ์œผ๋กœ ์ปค๋งํ•œ ํ›„์— ์žƒ์€ ๊ฒƒ์€ ์—†์œผ๋ฉฐ, log๋Š” ์•„์ง ๋ณดํ†ต๋•Œ์ฒ˜๋Ÿผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ํ•˜์—ฌ partialํ•จ์ˆ˜๋ฅผ ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•˜์—ฌ ๊ณ ์ • ๊ฐ’๋“ค์€ ๊ณ ์ •์‹œ์ผœ ์›ํ•˜๋Š” ๊ฐ’๋งŒ ๋„์ถœ๋˜๊ฒŒํ•˜์—ฌ ๋””๋ฒ„๊น…ํ•˜๋Š”๋ฐ ํŽธ๋ฆฌํ•˜๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

๐ŸŒธ ์ผ๋ฐ˜ ํ•จ์ˆ˜์™€ ์ฃผ์š” ์ฐจ์ด์ 

๐Ÿฃ ํ˜ธ์ถœ ๋ฐฉ์‹:

  • ์ผ๋ฐ˜ ํ•จ์ˆ˜: func(a, b, c)
  • ์ปค๋ง ํ•จ์ˆ˜: func(a)(b)(c)

๐Ÿฃ ์žฌ์‚ฌ์šฉ์„ฑ:

  • ์ผ๋ฐ˜ ํ•จ์ˆ˜: ๋งค๋ฒˆ ๋ชจ๋“  ์ธ์ž๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•จ
  • ์ปค๋ง ํ•จ์ˆ˜: ๋ถ€๋ถ„์ ์œผ๋กœ ์ ์šฉํ•˜์—ฌ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜ ์ƒ์„ฑ ๊ฐ€๋Šฅ

๐Ÿฃ ์œ ์—ฐ์„ฑ:

  • ์ผ๋ฐ˜ ํ•จ์ˆ˜: ์ธ์ž ์ˆœ์„œ๊ฐ€ ๊ณ ์ •๋จ
  • ์ปค๋ง ํ•จ์ˆ˜: ์ธ์ž๋ฅผ ๋‹จ๊ณ„๋ณ„๋กœ ์ ์šฉ ๊ฐ€๋Šฅ

๐ŸŒˆ lodash๋ฅผ ํ†ตํ•œ ์ปค๋ง

lodash๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข€ ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ์ปค๋ง์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐ŸŒธ lodash Syntax

_.curry(func, [arity=func.length])

๐ŸŒธ lodash Arguments

func (Function) โˆ’ The function to curry.

[arity=func.length] (number) โˆ’ The arity of func.

๐ŸŒธ lodash Output

(Function) โˆ’ Returns the new curried function.

example 1.

const _ = require('lodash');
const getArray = function(a, b, c) {
   return [a, b, c];
};
 
const curried = _.curry(getArray);
console.log(curried(1)(2)(3));
console.log(curried(1, 2)(3));
console.log(curried(1, 2, 3));

lodash ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ curryํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ •์˜ํ•  ํ•„์š” ์—†์ด, _.curry๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•˜์—ฌ curriedSum์„ ์ •์˜ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

example 2.

1) ๋ฌธ์ž์—ด ์ฒ˜๋ฆฌ ํ•จ์ˆ˜

const _ = require('lodash');

function concatenateStrings(a, b, c) {
  return `${a} ${b} ${c}`;
}

const curriedConcat = _.curry(concatenateStrings);

// ๋ถ€๋ถ„ ์ ์šฉ ์˜ˆ์ œ
const greet = curriedConcat('์•ˆ๋…•ํ•˜์„ธ์š”');
const greetTo = greet('๊น€์ฒ ์ˆ˜๋‹˜');

console.log(greetTo('๋ฐ˜๊ฐ‘์Šต๋‹ˆ๋‹ค!')); // "์•ˆ๋…•ํ•˜์„ธ์š” ๊น€์ฒ ์ˆ˜๋‹˜ ๋ฐ˜๊ฐ‘์Šต๋‹ˆ๋‹ค!"

2) API ์š”์ฒญ ํ•จ์ˆ˜

const _ = require('lodash');
const axios = require('axios');

function fetchAPI(baseURL, endpoint, params) {
  return axios.get(`${baseURL}/${endpoint}`, { params });
}

const curriedFetch = _.curry(fetchAPI);

// API ๊ธฐ๋ณธ ์„ค์ •
const fetchMyAPI = curriedFetch('https://api.example.com');

// ํŠน์ • ์—”๋“œํฌ์ธํŠธ์— ๋Œ€ํ•œ ํ•จ์ˆ˜ ์ƒ์„ฑ
const getUser = fetchMyAPI('users');
const getProduct = fetchMyAPI('products');

// ์‚ฌ์šฉ ์˜ˆ
getUser({ id: 123 })
  .then(response => console.log(response.data))
  .catch(error => console.error(error));

getProduct({ category: 'electronics' })
  .then(response => console.log(response.data))
  .catch(error => console.error(error));

3) ์ธ์ž ์ˆœ์„œ ๋ณ€๊ฒฝ (placeholder ์‚ฌ์šฉ)

const _ = require('lodash');

function divide(a, b) {
  return a / b;
}

const curriedDivide = _.curry(divide);

// ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ
const divideBy10 = curriedDivide(_, 10); // ์ฒซ ๋ฒˆ์งธ ์ธ์ž ๋‚˜์ค‘์— ๋ฐ›์Œ

console.log(divideBy10(100)); // 10 (100 / 10)

4) ๊ฐ์ฒด ๋ณ€ํ™˜ ํ•จ์ˆ˜

const _ = require('lodash');

function createUser(role, name, age) {
  return {
    role,
    name,
    age,
    id: Math.random().toString(36).substr(2, 9)
  };
}

const curriedCreateUser = _.curry(createUser);

// ๊ด€๋ฆฌ์ž ์ƒ์„ฑ ํ•จ์ˆ˜
const createAdmin = curriedCreateUser('admin');

// ํŠน์ • ์—ฐ๋ น๋Œ€ ๊ด€๋ฆฌ์ž ์ƒ์„ฑ
const createAdminIn30s = createAdmin(_, 35);

console.log(createAdminIn30s('๊น€๊ด€๋ฆฌ์ž'));
/*
{
  role: 'admin',
  name: '๊น€๊ด€๋ฆฌ์ž',
  age: 35,
  id: '4f6g7h8j9'
}
*/

5) ๋ฉ”๋ชจ์ด์ œ์ด์…˜๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ

const _ = require('lodash');

function expensiveCalculation(a, b, c) {
  console.log('๊ณ„์‚ฐ ์ˆ˜ํ–‰ ์ค‘...');
  // ๋ณต์žกํ•œ ๊ณ„์‚ฐ ๊ฐ€์ •
  return a * b * c;
}

const curriedCalculation = _.curry(expensiveCalculation);
const memoizedCalculation = _.memoize(curriedCalculation);

// ์ฒซ ํ˜ธ์ถœ - ๊ณ„์‚ฐ ์ˆ˜ํ–‰
console.log(memoizedCalculation(2)(3)(4)); // 24, "๊ณ„์‚ฐ ์ˆ˜ํ–‰ ์ค‘..." ์ถœ๋ ฅ

// ๋™์ผ ์ธ์ž๋กœ ์žฌํ˜ธ์ถœ - ์บ์‹œ๋œ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
console.log(memoizedCalculation(2)(3)(4)); // 24, ์ถœ๋ ฅ ์—†์Œ

6) ํ•จ์ˆ˜ ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์„ฑ

const _ = require('lodash');

// ๋ณ€ํ™˜ ํ•จ์ˆ˜๋“ค
function add(a, b) { return a + b; }
function multiply(a, b) { return a * b; }
function square(n) { return n * n; }

// ์ปค๋ง ์ ์šฉ
const curriedAdd = _.curry(add);
const curriedMultiply = _.curry(multiply);

// ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์„ฑ
const calculate = _.flow([
  curriedAdd(10),     // ์ฒซ ๋ฒˆ์งธ ์ธ์ž์— 10์„ ๋”ํ•จ
  curriedMultiply(5), // ๊ฒฐ๊ณผ์— 5๋ฅผ ๊ณฑํ•จ
  square              // ๊ฒฐ๊ณผ๋ฅผ ์ œ๊ณฑํ•จ
]);

console.log(calculate(5)); // ((5 + 10) * 5)^2 = 5625

7) ๊ฒ€์ƒ‰ ํ•„ํ„ฐ๋ง

const _ = require('lodash');

// ์ œํ’ˆ ๋ฐ์ดํ„ฐ
const products = [
  { id: 1, name: '๋…ธํŠธ๋ถ', category: '์ „์ž์ œํ’ˆ', price: 1200000 },
  { id: 2, name: '์Šค๋งˆํŠธํฐ', category: '์ „์ž์ œํ’ˆ', price: 800000 },
  { id: 3, name: '์˜์ž', category: '๊ฐ€๊ตฌ', price: 150000 },
  { id: 4, name: '์ฑ…์ƒ', category: '๊ฐ€๊ตฌ', price: 200000 }
];

// ํ•„ํ„ฐ ํ•จ์ˆ˜
function filterByCategory(category, items) {
  return items.filter(item => item.category === category);
}

function filterByMaxPrice(maxPrice, items) {
  return items.filter(item => item.price <= maxPrice);
}

// Lodash ์ปค๋ง ์ ์šฉ
const curriedFilterByCategory = _.curry(filterByCategory);
const curriedFilterByPrice = _.curry(filterByMaxPrice);

// ์นดํ…Œ๊ณ ๋ฆฌ ํ•„ํ„ฐ ์ƒ์„ฑ
const filterElectronics = curriedFilterByCategory('์ „์ž์ œํ’ˆ');
const filterFurniture = curriedFilterByCategory('๊ฐ€๊ตฌ');

// ๊ฐ€๊ฒฉ ํ•„ํ„ฐ ์ƒ์„ฑ
const filterUnder1Million = curriedFilterByPrice(1000000);

// ํ•„ํ„ฐ ์กฐํ•ฉ
const getAffordableElectronics = _.flow([
  filterElectronics,
  filterUnder1Million
]);

console.log(getAffordableElectronics(products));
/*
[
  { id: 2, name: '์Šค๋งˆํŠธํฐ', category: '์ „์ž์ œํ’ˆ', price: 800000 }
]
*/

Lodash์˜ _.curry ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด:

  • ๊ธฐ์กด ํ•จ์ˆ˜๋ฅผ ์‰ฝ๊ฒŒ ์ปค๋งํ•  ์ˆ˜ ์žˆ์Œ
  • ์ธ์ž๋ฅผ ์›ํ•˜๋Š” ์ˆœ์„œ๋Œ€๋กœ ๋ถ€๋ถ„ ์ ์šฉ ๊ฐ€๋Šฅ
  • _ ํ”Œ๋ ˆ์ด์Šค ํ™€๋”๋กœ ํŠน์ • ์ธ์ž๋งŒ ๋‚˜์ค‘์— ์ „๋‹ฌ ๊ฐ€๋Šฅ
  • ํ•จ์ˆ˜ ์กฐํ•ฉ์„ฑ์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋จ

์ปค๋ง์€ ํŠนํžˆ ๋ณต์žกํ•œ ํ•จ์ˆ˜ ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์„ฑํ•˜๊ฑฐ๋‚˜ ๊ณ ์ฐจ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค ๋•Œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐ŸŒˆ Lodash ์‚ฌ์šฉ ๊ฐ์†Œ ์ถ”์„ธ์˜ ์ฃผ์š” ์ด์œ 

๐ŸŒธ ES6+์˜ ๋ฐœ์ „:

  • ์ตœ์‹  JavaScript(ES6+)์—์„œ Lodash์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ๋“ค(map, filter, reduce ๋“ฑ)์ด ๋Œ€๋ถ€๋ถ„ ๊ธฐ๋ณธ ์ œ๊ณต๋˜๋ฉด์„œ ํ•„์š”์„ฑ์ด ๊ฐ์†Œ
  • ์˜ˆ: _.find() ๋Œ€์‹  Array.prototype.find() ์‚ฌ์šฉ ๊ฐ€๋Šฅ

๐ŸŒธ ์„ฑ๋Šฅ ์ฐจ์ด:

๋Œ€๋ถ€๋ถ„์˜ ๊ธฐ๋ณธ ์—ฐ์‚ฐ์—์„œ ๋„ค์ดํ‹ฐ๋ธŒ JavaScript๊ฐ€ ๋” ๋น ๋ฅธ ์„ฑ๋Šฅ์„ ๋ณด์ž„
๋‹จ, .uniq(), .throttle() ๋“ฑ ์ผ๋ถ€ ํ•จ์ˆ˜๋Š” ์—ฌ์ „ํžˆ Lodash๊ฐ€ ์šฐ์ˆ˜ํ•œ ๊ฒฝ์šฐ ์žˆ์Œ59

๐ŸŒธ ๋ฒˆ๋“ค ํฌ๊ธฐ ๋ฌธ์ œ:

ํŠธ๋ฆฌ ์‰์ดํ‚น์ด ์™„๋ฒฝํ•˜์ง€ ์•Š์•„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜๋„ ๋ฒˆ๋“ค์— ํฌํ•จ๋  ์ˆ˜ ์žˆ์Œ6

ํŠนํžˆ ํ”„๋ก ํŠธ์—”๋“œ ํ™˜๊ฒฝ์—์„œ ๋ฒˆ๋“ค ํฌ๊ธฐ ๋ฏผ๊ฐํ•  ๋•Œ ๋ฌธ์ œ๋จ

๐ŸŒธ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ง€์› ๋ฌธ์ œ:

  • JavaScript๋กœ ์ž‘์„ฑ๋˜์–ด ํƒ€์ž… ์ •์˜๊ฐ€ ๋ณ„๋„๋กœ ํ•„์š”(@types/lodash)
  • ํƒ€์ž… ์•ˆ์ •์„ฑ์ด ๋‚ฎ์•„ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜ ๊ฐ€๋Šฅ์„ฑ ์กด์žฌ

๐ŸŒˆ ์—ฌ์ „ํžˆ Lodash๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ

๐ŸŒธ ๋ ˆ๊ฑฐ์‹œ ํ”„๋กœ์ ํŠธ:

๊ธฐ์กด์— Lodash์— ์˜์กดํ•˜๋Š” ๋Œ€ํ˜• ํ”„๋กœ์ ํŠธ๋“ค์€ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋น„์šฉ ๋•Œ๋ฌธ์— ๊ณ„์† ์‚ฌ์šฉ

๐ŸŒธ ํŠน์ˆ˜ ๊ธฐ๋Šฅ ํ•„์š” ์‹œ:

  • .debounce(), .throttle() ๊ฐ™์€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜
  • _.cloneDeep() ๊ฐ™์€ ๊นŠ์€ ๋ณต์‚ฌ ๊ธฐ๋Šฅ
  • .groupBy(), .orderBy() ๋“ฑ ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ

๐ŸŒธ ํฌ๋กœ์Šค ๋ธŒ๋ผ์šฐ์ง•:

  • ์˜ค๋ž˜๋œ ๋ธŒ๋ผ์šฐ์ € ์ง€์›์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ

๐ŸŒˆ ํ˜„์‹ค์ ์ธ ์„ ํƒ ๊ฐ€์ด๋“œ

โœ… Lodash๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ:

  • ๊ฐ„๋‹จํ•œ ๋ฐฐ์—ด/๊ฐ์ฒด ์กฐ์ž‘์€ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์†Œ๋“œ ์‚ฌ์šฉ
  • [...new Set(arr)]์œผ๋กœ ์ค‘๋ณต ์ œ๊ฑฐ
  • Object.entries()๋กœ ๊ฐ์ฒด ์ˆœํšŒ

โš ๏ธ Lodash๋ฅผ ๊ณ ๋ คํ•ด๋ณผ ๊ฒฝ์šฐ:

  • ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ ํ•„์š” ์‹œ
  • ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ Lodash๊ฐ€ ์šฐ์ˆ˜ํ•œ ๊ฒฝ์šฐ
  • ์ด๋ฏธ Lodash์— ์ต์ˆ™ํ•œ ํŒ€์˜ ์ƒ์‚ฐ์„ฑ ํ–ฅ์ƒ์„ ์œ„ํ•ด

๐ŸŒธ ๋Œ€์•ˆ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”์ฒœ

  • lodash-es: ESM ๋ชจ๋“ˆ ์ง€์› ๋ฒ„์ „
  • ramda: ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ํŠนํ™”
  • remeda: ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ตœ์ ํ™” ์œ ํ‹ธ๋ฆฌํ‹ฐ
  • just: ํŠน์ • ๊ธฐ๋Šฅ๋งŒ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋ชจ๋“ˆ์‹ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

๐ŸŒˆ ๊ฒฐ๋ก 

์ปค๋ง์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ์ผ๋ฐ˜ ํ•จ์ˆ˜๊ฐ€ ๋” ์ง๊ด€์ ์ด๊ณ  ๊ฐ„๋‹จํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์ง€๋งŒ, ์ปค๋ง์€ ํ•จ์ˆ˜์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ์กฐํ•ฉ์„ฑ์„ ๋†’์—ฌ์ฃผ๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

Lodash๋Š” ์ ์  ํ•„์ˆ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ "์„ ํƒ์ " ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋ณ€ํ™” ์ค‘์ž…๋‹ˆ๋‹ค. 2025๋…„ ํ˜„์žฌ๋Š” ์ „์ฒด ๋ฒˆ๋“ค์„ ์„ค์น˜ํ•˜๊ธฐ๋ณด๋‹ค๋Š” ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ์„ ํƒ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, ๋„ค์ดํ‹ฐ๋ธŒ ๊ธฐ๋Šฅ์œผ๋กœ ๋Œ€์ฒดํ•˜๋Š” ์ถ”์„ธ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ ์‹ ๊ทœ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์ตœ์‹  JavaScript ๊ธฐ๋Šฅ์„ ์šฐ์„ ์ ์œผ๋กœ ๊ณ ๋ คํ•œ ํ›„, ๋ถ€์กฑํ•œ ๋ถ€๋ถ„๋งŒ Lodash๋‚˜ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋ณด์™„ํ•˜๋Š” ์ ‘๊ทผ์ด ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค.

"๊ณผ๊ฑฐ์—๋Š” Lodash๊ฐ€ ํ•„์ˆ˜์˜€์ง€๋งŒ, ์ด์ œ๋Š” ์„ ํƒ์˜ ๋ฌธ์ œ๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ ์š”๊ตฌ์‚ฌํ•ญ๊ณผ ํŒ€์˜ ์ˆ™๋ จ๋„๋ฅผ ๊ณ ๋ คํ•ด ํ˜„๋ช…ํ•˜๊ฒŒ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค."

๐ŸŒˆ ์ฐธ๊ณ  ์ž๋ฃŒ

https://ko.javascript.info/currying-partials
https://wiki.haskell.org/index.php?title=Currying
https://velog.io/@hustle-dev/Javascript-%EC%BB%A4%EB%A7%81%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90
https://www.tutorialspoint.com/lodash/lodash_curry.htm
https://if1live.github.io/posts/escape-from-lodash-just/

profile
So that my future self will not be ashamed of myself.

0๊ฐœ์˜ ๋Œ“๊ธ€