๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

๐ŸŒˆ Chapter 7: ํ•จ์ˆ˜ํ˜• ์ตœ์ ํ™”

๐Ÿ“š ํ•จ์ˆ˜ ์‹คํ–‰์˜ ๋‚ด๋ถ€ ์ž‘๋™ ์›๋ฆฌโ€‹

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ํ•จ์ˆ˜ ์ฝ˜ํ…์ŠคํŠธ ์Šคํƒ์— ๋ ˆ์ฝ”๋“œ(ํ”„๋ ˆ์ž„) ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.
  • ์ฝ˜ํ…์ŠคํŠธ ์Šคํƒ์€ ํ•จ์ˆ˜ ์‹คํ–‰ ๋ฐ ํ•จ์ˆ˜๊ฐ€ ์—์›Œ์‹ผ(ํด๋กœ์ € ๊ฐ™์€ ๊ฒƒ) ๋ณ€์ˆ˜๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ์ด๋‹ค.
  • ์Šคํƒ์€ ์–ธ์ œ๋‚˜ ์ „์—ญ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ด๊ธด, ์ „์—ญ ์‹คํ–‰ ์ฝ˜ํ…์ŠคํŠธ ํ”„๋ ˆ์ž„์—์„œ ์‹œ์ž‘ํ•œ๋‹ค.
  • ์ „์—ญ ์ฝ˜ํ…์ŠคํŠธ ํ”„๋ ˆ์ž„์€ ํ•ญ์ƒ ์Šคํƒ ๋งจ ๋ฐ‘์— ์œ„์น˜ํ•œ๋‹ค. ์ง€์—ญ ๋ณ€์ˆ˜๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋Š” ๋นˆ ํ”„๋ ˆ์ž„์€ 48๋น„ํŠธ ์ •๋„ ๋˜๊ณ , ์ˆซ์ž, ๋ถˆ๋ฆฌ์–ธ ๊ฐ™์€ ์ง€์—ญ ๋ณ€์ˆ˜/๋งค๊ฐœ๋ณ€์ˆ˜๋Š” 8๋ฐ”์ดํŠธ๋ฅผ ์ฐจ์ง€ํ•œ๋‹ค.
executionContextData = {
scopeChain, // ์ด ํ•จ์ˆ˜์˜ variableObject, ๊ทธ๋ฆฌ๊ณ  ๋ถ€๋ชจ ์‹คํ–‰ ์ฝ˜ํ…์ŠคํŠธ์˜ variableObject์— ์ ‘๊ทผํ•˜๋Š” ์—ฐ๊ฒฐ ๊ณ ๋ฆฌ์ด๋‹ค.
variableObject, // ํ•จ์ˆ˜์˜ ์ธ์ˆ˜, ๋‚ด๋ถ€ ๋ณ€์ˆ˜, ํ•จ์ˆ˜ ์„ ์–ธ๋ถ€๋ฅผ ํฌํ•จํ•œ๋‹ค.
this // ํ•จ์ˆ˜ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ ˆํผ๋Ÿฐ์Šค
}
  • variableObject๋Š” ์ง€์—ญ ๋ณ€์ˆ˜์™€ ํ•จ์ˆ˜๋Š” ๋ฌผ๋ก , ํ•จ์ˆ˜์˜ ์ธ์ˆ˜, ์œ ์‚ฌ๋ฐฐ์—ด ๊ฐ์ฒด arguments๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์†์„ฑ์ด๋ฏ€๋กœ, ์‚ฌ์‹ค์ƒ ์Šคํƒ ํ”„๋ ˆ์ž„์˜ ํฌ๊ธฐ๋Š” ์ด ์†์„ฑ์œผ๋กœ ๊ฒฐ์ •๋œ๋‹ค.
  • ์Šค์ฝ”ํ”„ ์ฒด์ธ์€ ์ด ํ•จ์ˆ˜์˜ ์ฝ˜ํ…์ŠคํŠธ๋ฅผ ๊ทธ ๋ถ€๋ชจ ์‹คํ–‰ ์ฝ˜ํ…์ŠคํŠธ์™€ ์—ฐ๊ฒฐํ•˜๊ฑฐ๋‚˜ ์ฐธ์กฐํ•œ๋‹ค.
  • ๋ชจ๋“  ํ•จ์ˆ˜๋Š” ์Šค์ฝ”ํ”„ ์ฒด์ธ์ด ๊ฒฐ๊ตญ ์ง/๊ฐ„์ ‘์ ์œผ๋กœ ์ „์—ญ ์ฝ˜ํ…์ŠคํŠธ์™€ ์—ฐ๊ฒฐ๋œ๋‹ค.
  • ๐Ÿ“Œ ์Šคํƒ์˜ ์ฃผ์š” ์ž‘๋™ ๊ทœ์น™
    1. ์ž๋ฐ”ํฌ๋ฆฝํŠธ๋Š” ๋‹จ์ผ ์Šค๋ ˆ๋“œ๋กœ ์ž‘๋™ํ•œ๋‹ค. ์ฆ‰, ๋™๊ธฐ ์‹คํ–‰ ๋ฐฉ์‹์ด๋‹ค.
    2. ์ „์—ญ ์ฝ˜ํ…์ŠคํŠธ๋Š” ๋‹จ ํ•˜๋‚˜๋งŒ ์กด์žฌํ•œ๋‹ค. (๋ชจ๋“  ํ•จ์ˆ˜ ์ฝ˜ํ…์ŠคํŠธ๋Š” ์ „์—ญ ์ฝ˜ํ…์ŠคํŠธ๋ฅผ ๊ณต์œ ํ•œ๋‹ค.)
    3. ํ•จ์ˆ˜ ์ฝ˜ํ…์ŠคํŠธ ๊ฐœ์ˆ˜๋Š” ์ œํ•œ์€ ์—†๋‹ค.
    4. ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰ ์ฝ˜ํ…์ŠคํŠธ๊ฐ€ ์ƒˆ๋กœ ์ƒ์„ฑ๋˜๋ฉฐ, ์ž๊ธฐ ์ž์‹ ์„ ์žฌ๊ท€ ํ˜ธ์ถœํ•  ๋•Œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค.
  • ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ํ•จ์ˆ˜๋ฅผ ์ตœ๋Œ€ํ•œ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•˜๋ฏ€๋กœ, ์œ ์—ฐ์„ฑ๊ณผ ์žฌ์‚ฌ์šฉ์„ ๋Š˜๋ฆฌ๊ณ ์ž ๋‹น๋ฉดํ•œ ๋ฌธ์ œ๋ฅผ ๊ฐ€๋Šฅํ•œ ํ•œ ๋งŽ์€ ํ•จ์ˆ˜๋กœ ๋ถ„ํ•ดํ•˜๊ณ  ์ปค๋ฆฌํ•˜๋Š” ๊ฑด ์–ผ๋งˆ๋“ ์ง€ ์ข‹์ง€๋งŒ, ์ปค๋ฆฌ๋œ ํ•จ์ˆ˜๋ฅผ ์ง€๋‚˜์น˜๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ˜ํ…์ŠคํŠธ ์Šคํƒ์— ์–ด๋–ค ์‹์œผ๋กœ๋“  ์˜ํ–ฅ์„ ๋ผ์นœ๋‹ค.

๐ŸŽˆ ์ปค๋ง๊ณผ ํ•จ์ˆ˜ ์ฝ˜ํ…์ŠคํŠธ ์Šคํƒโ€‹

  • ์ถ”์ƒํ™”๋ฅผ ํ•œ ๊บผํ’€ ๋” ์ž…ํžˆ๋ฉด ์ผ๋ฐ˜์ ์ธ ํ•จ์ˆ˜ ํ‰๊ฐ€๋ณด๋‹ค ์ฝ˜ํ…์ŠคํŠธ ์˜ค๋ฒ„ํ•ด๋“œ๊ฐ€ ๋” ๋งŽ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
const logger = function(appender, layout, layout, name, level, message);
// ...

const logger =
function (appender) {
return function (layout) {
return function (name) {
return function (level) {
return function (message) {
// ...
}
}
}
}
}
  • ์œ„์™€ ๊ฐ™์€ ์ค‘์ฒฉ ๊ตฌ์กฐ๋Š” ํ•œ ๋ฒˆ์— ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ ๋ณด๋‹ค ํ•จ์ˆ˜ ์Šคํƒ์„ ๋” ๋งŽ์ด ์“ด๋‹ค.
  • logger ํ•จ์ˆ˜๋ฅผ ์ปค๋ง ์—†์ด ์‹คํ–‰ํ•˜๋ฉด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋™๊ธฐ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ์šฐ์„  ์ „์—ญ ์ฝ˜ํ…์ŠคํŠธ ์‹คํ–‰์„ ์ž ์‹œ ๋ฉˆ์ถ”๊ณ  ์ƒˆ ํ™œ์„ฑ ์ฝ˜ํ…์ŠคํŠธ๋ฅผ ๋งŒ๋“  ๋‹ค์Œ, ๋ณ€์ˆ˜ ํ•ด์„์— ์‚ฌ์šฉํ•  ์ „์—ญ ์ฝ˜ํ…์ŠคํŠธ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
  • logger ํ•จ์ˆ˜๋Š” ๊ทธ ์•ˆ์—์„œ ๋‹ค๋ฅธ Log4js ์—ฐ์‚ฐ์„ ํ˜ธ์ถœํ•˜๋ฏ€๋กœ ์ƒˆ ํ•จ์ˆ˜ ์ฝ˜ํ…์ŠคํŠธ๊ฐ€ ์ƒ์„ฑ๋˜์–ด ์Šคํƒ์— ์Œ“์ธ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํด๋กœ์ € ๋–„๋ฌธ์— ๋‚ด๋ถ€ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ๋น„๋กฏ๋œ ํ•จ์ˆ˜ ์ฝ˜ํ…์ŠคํŠธ๋Š” ๋‹ค๋ฅธ ์ฝ˜ํ…์ŠคํŠธ ์œ„์— ์ฐจ๊ณก์ฐจ๊ณก ์Œ“์ด๋ฉฐ, ๊ฐ ์ฝ˜ํ…์ŠคํŠธ๋Š” ์ผ์ • ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ฐจ์ง€ํ•œ ์ฑ„ scopeChain ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ๋œ๋‹ค.
  • ์ค‘์ฒฉ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ด๋Ÿฐ ์‹์œผ๋กœ ํ•จ์ˆ˜ ์ฝ˜ํ…์ŠคํŠธ๊ฐ€ ์ฆ๊ฐ€ํ•˜๊ณ , ํ•จ์ˆ˜๋งˆ๋‹ค ์Šคํƒ ํ”„๋ ˆ์ž„์ด ์ƒˆ๋กœ ์ƒ๊ธฐ๋ฏ€๋กœ ํ•จ์ˆ˜๊ฐ€ ์ค‘์ฒฉ๋œ ์ •๋ณด๋งŒํผ ์Šคํƒ์ด ์ปค์ง„๋‹ค. ์ปค๋ง๊ณผ ์žฌ๊ท€๋Š” ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์ค‘์ฒฉํ•˜์—ฌ ์ž‘๋™ํ•œ๋‹ค.
  • ๋‹ค์‹œ ์‹คํ–‰์ด ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰์ด ์™„๋ฃŒ๋˜๋ฉด ๋Ÿฐํƒ€์ž„์€ ๋‹ค์‹œ ์ฒ˜์Œ ์ƒํƒœ๋กœ ๋Œ์•„๊ฐ€๊ณ  ์ „์—ญ ์ฝ˜ํ…์ŠคํŠธ ๋‹จ ํ•˜๋‚˜๋งŒ ์‹คํ–‰ ์ƒํƒœ๋กœ ๋‚จ๋Š”๋‹ค. ์ด๊ฒƒ์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํด๋กœ์ €๋ผ๋Š” ๊ฒƒ์ด๋‹ค.
  • ๋ชจ๋“  ํ•จ์ˆ˜๋ฅผ ์ปค๋ฆฌํ•˜๋ฉด ํ•ญ์ƒ ์ข‹์„ ๊ฒƒ ๊ฐ™์ง€๋งŒ, ๊ณผ์šฉํ•˜๋ฉด ์—„์ฒญ๋‚œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์†Œ๋ชจ๋˜๋ฉด์„œ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์†๋„๊ฐ€ ํ˜„์ €ํžˆ ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.
const add = function (a, b) {
return a + b;
};

const c_add = curry2(add);

const input = _.range(80000);

addAll(input, add); // -> 511993600000000
addAll(input, c_add); // -> ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ป—์Œ

function addAll(arr, fn) {
let result = 0;
for(let i = 0; i < arr.length; i++) {
for(let j = 0; j < arr.length; j++) {
result += fn(arr[i], arr[j]);
}
}
return result;
}

๐ŸŽˆ ์žฌ๊ท€ ์ฝ”๋“œ์˜ ๋ฌธ์ œ์ โ€‹

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

๐Ÿ“š ๋Š๊ธ‹ํ•œ ํ‰๊ฐ€๋กœ ์‹คํ–‰์„ ๋Šฆ์ถคโ€‹

  • ๋ถˆํ•„์š”ํ•œ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์‚ผ๊ฐ€๊ณ  ๊ผญ ํ•„์š”ํ•œ ์ž…๋ ฅ๋งŒ ๋„ฃ๊ณ  ์‹คํ–‰ํ•˜๋ฉด ์—ฌ๋Ÿฌ๋ชจ๋กœ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ•˜์Šค์ผˆ ๊ฐ™์€ ํ•จ์ˆ˜ํ˜• ์–ธ์–ด๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ํ•จ์ˆ˜ ํ‰๊ฐ€์‹์„ ๋Š๊ธ‹ํ•˜๊ฒŒ ํ‰๊ฐ€(lazy function evaluation) ํ•˜๋„๋ก ์ง€์›ํ•œ๋‹ค.
  • ๋Š๊ธ‹ํ•œ ํ‰๊ฐ€๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ „๋žต์ด ์žˆ์ง€๋งŒ, ๊ฐ€๋Šฅํ•œ ํ•œ ์˜ค๋ž˜, ์˜์กดํ•˜๋Š” ํ‘œํ˜„์‹์ด ํ˜ธ์ถœ๋  ๋•Œ๊นŒ์ง€ ๋ฏธ๋ฃฌ๋‹ค๋Š” ๊ทผ๋ณธ ์‚ฌ์ƒ์€ ๊ฐ™๋‹ค.
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•จ์ˆ˜ ๊ฒฐ๊ด๊ฐ’์ด ํ•„์š”ํ•œ์ง€ ๋”ฐ์ ธ๋ณผ ์ƒˆ๋„ ์—†์ด ๋ณ€์ˆ˜์— ๋ฐ”์ธ๋”ฉ๋˜์ž๋งˆ์ž ํ‘œํ˜„์‹ ํ‰๊ฐ€๋ฅผ ๋งˆ์นœ๋‹ค. ๊ทธ๋ž˜์„œ ํƒ์š•์Šค๋Ÿฐ ํ‰๊ฐ€๋ผ๊ณ  ํ•œ๋‹ค.
  • ๋‹ค์Œ Maybe ๋ชจ๋‚˜๋“œ ์˜ˆ์ œ์ด๋‹ค.
// Maybe ๋ชจ๋‚˜๋“œ
Maybe.of(student).getOrElse(createNewStudent());

// ์•„๋ž˜์™€ ๊ฐ™์ด ์‹คํ–‰๋  ๊ฑฐ ๊ฐ™์ง€๋งŒ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ๊ทธ๋ ‡์ง€ ์•Š๋‹ค.
if(!student) {
return createNewStudent();
}
else {
return student;
}
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ์กฐ๊ธ‰ํ•˜๊ฒŒ ํ‰๊ฐ€ํ•˜๋ฏ€๋กœ ํ•™์ƒ ๊ฐ์ฒด๊ฐ€ null ์ด๋“  ์•„๋‹ˆ๋“  createNewStudent ํ•จ์ˆ˜๋ฅผ ๋ฌด์กฐ๊ฑด ์‹คํ–‰ํ•œ๋‹ค.
  • ๋Š๊ธ‹ํ•˜๊ฒŒ ํ‰๊ฐ€ํ•˜๋ฉด, ํ‘œํ˜„์‹์€ ์œ„ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜๊ฒ ์ง€๋งŒ ํ•™์ƒ ๊ฐ์ฒด๊ฐ€ ์ •์ƒ์ด ์•„๋‹ ๊ฒฝ์šฐ createNewStudent ํ•จ์ˆ˜๋Š” ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋Š๊ธ‹ํ•œ ํ‰๊ฐ€๋Š” ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์„๊นŒ?
    1. ๋ถˆํ•„์š”ํ•œ ๊ณ„์‚ฐ์„ ํ”ผํ•œ๋‹ค.
    2. ํ•จ์ˆ˜ํ˜• ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ๋‹จ์ถ• ์œตํ•ฉ(shortcut fusion)์„ ์‚ฌ์šฉํ•œ๋‹ค.

๐ŸŽˆ ๋Œ€์ฒด ํ•จ์ˆ˜ํ˜• ์กฐํ•ฉ์œผ๋กœ ๊ณ„์‚ฐ์„ ํšŒํ”ผโ€‹

  • ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ์šฉ๋ก€๋Š” ํ•จ์ˆ˜๋ฅผ ๋ ˆํผ๋Ÿฐ์Šค๋กœ ์ „๋‹ฌํ•˜๊ณ  ์กฐ๊ฑด์— ๋”ฐ๋ผ ํ•œ์ชฝ๋งŒ ํ˜ธ์ถœํ•˜์—ฌ ์“ธ๋ฐ์—†๋Š” ๊ณ„์‚ฐ์„ ๊ฑด๋„ˆ๋›ฐ๋Š” ๊ฒƒ์ด๋‹ค.
const alt = R.curry((func1 , func2, val) => func1(val) || func2(val));

const showStudent = R.compose(append('#student-info'),
alt(findStudent, createNewStudent)); // ํ•จ์ˆ˜๋ฅผ ์กฐ๊ธ‰ํ•˜๊ฒŒ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ , ํ•จ์ˆ˜๋ฅผ ๋ ˆํผ๋Ÿฐ์Šค๋กœ ์ „๋‹ฌํ•˜๊ณ  ์กฐํ•ฉ๊ธฐ๊ฐ€ ์‹คํ–‰์„ ์กฐ์ •ํ•œ๋‹ค.

showStudent('444-44-4444');
  • ํ•จ์ˆ˜ ์กฐํ•ฉ๊ธฐ๊ฐ€ ์•Œ์•„์„œ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ๊ด€์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ์ฝ”๋“œ๋Š” ๋‹ค์Œ ๋ช…๋ นํ˜• ์ฝ”๋“œ์™€ ๋˜‘๊ฐ™์ด ์ž‘๋™ํ•œ๋‹ค.
var student = findStudent('444-44-4444');
if(student !== null) {
append('#student-info', student);
}
else {
append('#student-info', createNewStudent('444-44-4444'));
}

๐ŸŽˆ ๋‹จ์ถ• ์œตํ•ฉ์„ ํ™œ์šฉโ€‹

  • ๋‹ค์Œ์€ ๋กœ๋Œ€์‹œ JS๋ฅผ ์‚ฌ์šฉํ•œ ๊ฑฐ์ฃผ ๊ตญ๊ฐ€๋ณ„ ์ธ์›์ˆ˜์— ๋”ฐ๋ผ ์ •๋ ฌํ•œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ์ฝ”๋“œ์ด๋‹ค.
_.chain([p1, p2, p3, p4, p5, p6, p7])
.filter(isValid)
.map(_.property('address.country')).reduce(gatherStats, {})
.values()
.sortBy('count')
.reverse()
.first()
.value()
  • ์ด์ฒ˜๋Ÿผ ์„ ์–ธ์ ์ธ ํ˜•ํƒœ๋กœ ํ”„๋กœ๊ทธ๋žจ์„ ์ž‘์„ฑํ•˜๋Š” ๊ฑด, ํ•˜๊ณ  ์‹ถ์€ ์ผ์„ ๋ฏธ๋ฆฌ ์ •์˜ํ•จ์œผ๋กœ์จ ํ•จ์ˆ˜๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋“  ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๊ณ  ๋ฌด์Šจ ์ผ์„ ํ•ด์•ผ ํ•˜๋Š”์ง€๋งŒ ๋ฐํžŒ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.
  • ๋•๋ถ„์— ๋‹จ์ถ• ์œตํ•ฉ์ด๋ผ๋Š” ๊ธฐ๋ฒ•์œผ๋กœ ๋กœ๋Œ€์‹œ JS๊ฐ€ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰์„ ๋‚ด๋ถ€์ ์œผ๋กœ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋‹จ์ถ• ์œตํ•ฉ์€ ๋ช‡ ๊ฐœ ํ•จ์ˆ˜์˜ ์‹คํ–‰์„ ํ•˜๋‚˜๋กœ ๋ณ‘ํ•ฉํ•˜๊ณ  ์ค‘๊ฐ„ ๊ฒฐ๊ณผ๋ฅผ ๊ณ„์‚ฐํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋‚ด๋ถ€ ์ž๋ฃŒ๊ตฌ์กฐ์˜ ๊ฐœ์ˆ˜๋ฅผ ์ค„์ด๋Š” ํ•จ์ˆ˜ ์ˆ˜์ค€์˜ ์ตœ์ ํ™”์ด๋‹ค.
  • ์ž๋ฃŒ๊ตฌ์กฐ๊ฐ€ ์ค„๋ฉด ๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ ํ•„์š”ํ•œ ๊ณผ๋„ํ•œ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์„ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ๋‹ค.
  • ๋‹ค์Œ์€ ๋กœ๋Œ€์‹œ JS์˜ ๋Š๊ธ‹ํ•œ ํ‰๊ฐ€ ๋ฐ ๋‹จ์ถ• ์œตํ•ฉ์„ ์‚ฌ์šฉํ•œ ๊ฒƒ์ด๋‹ค.
const square = (x) => Math.pow(x, 2);
const isEven = (x) => x % 2 === 0;
const numbers = _.range(200); // 1 ~ 200 ์‚ฌ์ด์˜ ์ˆซ์ž๋กœ ๊ตฌ์„ฑ๋œ ๋ฐฐ์—ด์„ ์ƒ์„ฑ

const result =
_.chain(numbers)
.map(square)
.filter(isEven)
.take(3) // filter ๊ธฐ์ค€์œผ๋กœ ๋งŒ์กฑํ•˜๋Š” ์ฒ˜์Œ ์„ธ ์ˆซ์ž๋งŒ ์ฒ˜๋ฆฌํ•œ๋‹ค.
.value(); // [0, 4, 16]

result.length; // 5

๐Ÿ“š 'ํ•„์š”ํ•  ๋•Œ ๋ถ€๋ฅด๋ฆฌ' ์ „๋žตโ€‹

  • ๋ฐ˜๋ณต์ ์ธ ๊ณ„์‚ฐ์„ ํ”ผํ•˜๋Š” ๊ฒƒ๋„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์†๋„๋ฅผ ๋Œ์–ด์˜ฌ๋ฆฌ๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ–ˆ์—ˆ๋‹ค.
  • ๋‹ค์Œ์€ ํ•จ์ˆ˜์— ์บ์‹œ ๊ณ„์ธต์„ ๊ฐ„๋‹จํžˆ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ์ด๋‹ค.
function cachedFn (cache, fn, args) {
// ํ•จ์ˆ˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ํ•จ์ˆ˜๋ช…๊ณผ ์ธ์ˆ˜๋ฅผ ์กฐํ•ฉํ•˜์—ฌ ํ‚ค๊ฐ’์„ ์ •ํ•œ๋‹ค.
let key = fn.name + JSON.stringify(args);
if (contains(cache, key)) {
return get(cache, key);
}
else {
let result = fn.apply(this, args); // ์บ์‹œ์— ๊ฐ’์ด ์—†์œผ๋ฉด ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. (์บ์‹œ ๋ฏธ์Šค)
put(cache, key, result); // ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œ์— ๋‹ด๋Š”๋‹ค.
return result;
}
}
  • findStudent ํ•จ์ˆ˜ ์‹คํ–‰์„ cachedFn์œผ๋กœ ๊ฐ์‹ธ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
var cache = {};
cachedFn(cache, findStudent, '444-44-4444'); // ์ฒ˜์Œ์—๋Š” ์บ์‹œ ๋ฏธ์Šค์ด๋ฏ€๋กœ findStudent๋ฅผ ์‹คํ–‰
cachedFn(cache, findStudent, '444-44-4444'); // ๋‘ ๋ฒˆ์งธ๋Š” ์บ์‹œ์— ๋ณด๊ด€๋œ ๊ฐ’์„ ๊ณง๋ฐ”๋กœ ์ฝ๋Š”๋‹ค.
  • ํ•˜์ง€๋งŒ ์ด๋Ÿฐ ํ•จ์ˆ˜์— ์ผ์ผ์ด ์ด๋Ÿฐ ๋ž˜ํผ๋ฅผ ๋‘๊ณ  ํ˜ธ์ถœํ•˜๊ฒŒ๋” ์ฝ”๋”ฉํ•˜๋Š” ๊ฑด ์ƒ๋‹นํžˆ ๋ฒ„๊ฒ๊ธฐ๋„ ํ•˜๊ณ  ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๊ณ , ๊ทธ๋ ‡๊ฒŒ ์ž‘์„ฑํ•œ ํ•จ์ˆ˜๋Š” ์ „์—ญ ๊ณต์œ  ์บ์‹œ ๊ฐ์ฒด์— ์˜์กดํ•˜๋Š” ๋ถ€์ˆ˜ํšจ๊ณผ๊ฐ€ ์žˆ๋‹ค.
  • ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜ํ˜• ์–ธ์–ด์—๋Š” ๋ฉ”๋ชจํ™”(memoization) ๋ผ๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์žˆ๋‹ค.

๐ŸŽˆ ๋ฉ”๋ชจํ™”โ€‹

  • ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ๋ฅผ ํ•ด๋‹น ์ž…๋ ฅ๊ณผ ์—ฐ๊ด€์‹œํ‚ค๋Š” ์ผ, ์ฆ‰ ๋‹ค์‹œ ๋งํ•ด, ํ•จ์ˆ˜์˜ ์ž…๋ ฅ์„ ์–ด๋–ค ๊ฐ’์œผ๋กœ ๊ณ„์‚ฐํ•ด๋‚ด๋Š” ๊ฑด ์–ด๋–ค ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์›๋ฆฌ ๋•๋ถ„์— ๊ฐ€๋Šฅํ• ๊นŒ? ๊ทธ๋ ‡๋‹ค. ๋ฐ”๋กœ ์ฐธ์กฐ ํˆฌ๋ช…์„ฑ์ด๋‹ค.

๐ŸŽˆ ๊ณ„์‚ฐ๋Ÿ‰์ด ๋งŽ์€ ํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจํ™”โ€‹

  • ์ˆœ์ˆ˜ ํ•จ์ˆ˜ํ˜• ์–ธ์–ด๋Š” ์ž๋™์œผ๋กœ ๋ฉ”๋ชจํ™”๋ฅผ ์‹ค์ฒœํ•˜์ง€๋งŒ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋‚˜ ํŒŒ์ด์ฌ ๊ฐ™์€ ์–ธ์–ด์—์„œ๋Š” ํ•จ์ˆ˜๋ฅผ ์–ธ์ œ ๋ฉ”๋ชจํ• ์ง€ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฌธ์ž์—ด ROT13 ํ˜•์‹์œผ๋กœ ์ธ์ฝ”๋”ฉํ•˜๋Š” rot13 ํ•จ์ˆ˜๋ฅผ ๋ณด์ž.
var discountCode = 'functional_js_50_off';

rot13(discountCode); // shapgvbany_wf_50_bss
  • ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ์ ์€ rot13 ํ•จ์ˆ˜์— ๋™์ผํ•œ ๋ฌธ์ž์—ด์„ ์ž…๋ ฅํ•˜๋ฉด ๋ฐ˜๋“œ์‹œ ๋™์ผํ•œ ๋ฌธ์ž์—ด์ด ์ถœ๋ ฅ๋œ๋‹ค (์ฆ‰, ์ฐธ์กฐ ํˆฌ๋ช…ํ•˜๋‹ค)๋Š” ์‚ฌ์‹ค์ด๋‹ค.
  • ๋ฐ”๊ฟ” ๋งํ•ด, ์ด ํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจํ•˜๋ฉด ์—„์ฒญ๋‚œ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฉ”๋ชจํ™”๋ฅผ ํ•˜๋ฉด ๋™์ผํ•œ ์ž…๋ ฅ์œผ๋กœ ํ•จ์ˆ˜๋ฅผ ์žฌํ˜ธ์ถœํ•  ๋•Œ ๋‚ด๋ถ€ ์บ์‹œ๊ฐ€ ํžˆํŠธ๋˜์–ด ์ฆ‰์‹œ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค.
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๊ณ ์ •๋ฐ€ ์‹œ๊ฐ API๊ฐ€ ๊ทธ ์˜ˆ์ด๋‹ค. ์ด API๋Š” Date.now(), console.time() ๊ฐ™์€ ๊ธฐ๋ณธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜๋ณด๋‹ค ๋” ์ •ํ™•ํ•œ ํƒ€์ž„์Šคํƒฌํ”„๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ  ํ•จ์ˆ˜ ํ˜ธ์ถœ ๊ฒฝ๊ณผ ์‹œ๊ฐ„์„ ์žด ์ˆ˜ ์žˆ๋‹ค.
  • ์‹œ๊ฐ„์„ ์žฌ๋Š” ํ˜ธ์ถœ์„ tap์œผ๋กœ ์ถ”๊ฐ€
const start = () => now();
const runs = [];
const end = function (start) {
let end = now();
let result = (end - start).toFixed(3);
runs.push(result);
return result;
};

const test = function (fn, input) {
return () => fn(input);
};

const testRot13 = IO.form(start)
// tap ์กฐํ•ฉ๊ธฐ๋กœ ๋ชจ๋‚˜๋“œ๋ฅผ ํ†ตํ•ด ์‹œ์ž‘ ์‹œ๊ฐ„ ์ •๋ณด๋ฅผ ์ „ํŒŒํ•œ๋‹ค.
.map(R.tap(test(rot13, 'functional_js_50_off')))
.map(end);

testRot13.run();
testRot13.run();
assert.ok(runs[0] >= runs[1]);
  • ํ•จ์ˆ˜ ํ˜ธ์ถœ์— ๋ฉ”๋ชจํ™” ์ถ”๊ฐ€
Function.prototype.memoized = function() {
let key = JSON.stringify(arguments);
// ๋‚ด๋ถ€ ์ง€์—ญ ์บ์‹œ๋ฅผ ๋งŒ๋“ ๋‹ค.
this._cache = this._cache || {};
// ์ด์ „์— ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•œ ์  ์žˆ๋Š”์ง€ ์บ์‹œ๋ฅผ ๋จผ์ € ์ฝ๊ณ  ๊ฐ’์ด ์žˆ์œผ๋ฉด ํ•จ์ˆ˜๋ฅผ ๊ฑด๋„ˆ๋›ฐ๊ณ 
// ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๊ฐ’์ด ์—†์œผ๋ฉด ๊ณ„์‚ฐ์„ ํ•œ๋‹ค.
this._cache[key] = this._cache[key] ||
this.apply(this, arguments);

return this._cache[key];
};

// ํ•จ์ˆ˜ ๋ฉ”๋ชจํ™”๋ฅผ ํ™œ์„ฑํ™”ํ•œ๋‹ค.
Function.prototype.memoize = function() {
let fn = this;
is(fn.length === 0 || fn.length > 1) {
return fn; // ๋‹จํ•ญ ํ•จ์ˆ˜๋งŒ ๋ฉ”๋ชจํ•œ๋‹ค.
}

return function () {
// ํ•จ์ˆ˜ ์ธ์Šคํ„ด์Šค๋ฅผ memoized ํ•จ์ˆ˜๋กœ ๊ฐ์‹ผ๋‹ค.
return fn.memoized.apply(fn, arguments);
}
}
  • ์œ„์™€ ๊ฐ™์ด Function ๊ฐ์ฒด๋ฅผ ํ™•์žฅํ•˜๋‹ˆ ์–ด๋””์„œ๊ฑด ๋ฉ”๋ชจํ™” ๊ธฐ๋Šฅ์„ ๊บผ๋‚ด ์“ธ ์ˆ˜ ์žˆ๊ณ  ์ „์—ญ ๊ณต์œ  ์บ์‹œ์— ์ ‘๊ทผํ•˜๋Š” ๊ธฐ์‹œ์ ์ธ ๋ถ€์ˆ˜ํšจ๊ณผ๊ฐ€ ์‚ฌ๋ผ์กŒ๋‹ค.
  • ๋˜ ํ•จ์ˆ˜์˜ ๋‚ด๋ถ€ ์บ์‹œ ์ฒด์ œ๋ฅผ ์ถ”์ƒํ•˜์—ฌ ํ…Œ์ŠคํŠธ์™€ ์™„์ „ํžˆ ๋ฌด๊ด€ํ•œ ์ฝ”๋“œ๋กœ ๋งŒ๋“ค์—ˆ๋‹ค.
  • ์—ฌ๋Ÿฌ ์ธ์ˆ˜๋ฅผ ๋ฐ›๋Š” ํ•จ์ˆ˜์˜ ๋ฉ”๋ชจํ™” ๊ณผ์ •์—๋Š” ์•„๋ฌด๋ž˜๋„ ์ ํ•ฉํ•œ ์บ์‹œํ‚ค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ž‘์—…์ด ๋ณต์žกํ•˜๊ณ  ๋น„์‹ผ ์—ฐ์‚ฐ์„ ์ˆ˜๋ฐ˜ํ•˜๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿด ๋•Œ ์ปค๋ง์„ ์‚ฌ์šฉํ•œ๋‹ค.

๐ŸŽˆ ์ปค๋ง๊ณผ ๋ฉ”๋ชจํ™”๋ฅผ ํ™œ์šฉโ€‹

  • ๋ณต์žกํ•œ ํ•จ์ˆ˜, ์ฆ‰ ์ธ์ˆ˜๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์ธ ํ•จ์ˆ˜๋Š” ์•„๋ฌด๋ฆฌ ์ˆœ์ˆ˜ํ•จ์ˆ˜๋ผ ํ•ด๋„ ์บ์‹œํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค.
  • ํ•œ ๊ฐ€์ง€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์ปค๋ง์ด๋‹ค.
// ์ด ํ•จ์ˆ˜๋Š” ์ฐธ์กฐ ํˆฌ๋ช…ํ•˜์ง€ ์•Š์ง€๋งŒ, ์‹ค์ œ๋กœ ๊ฐ’๋น„์‹ผ ๊ฒ€์ƒ‰์ด๋‚˜ ์›๊ฒฉ HTTP ์š”์ฒญ์„ ํ•  ๋•Œ๋Š” ๋ณดํ†ต ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.
const safeFindObject = R.curry(function (db, ssn) {
// ๊ฐ’๋น„์‹ผ IO ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰
});

const findStudent = safeFindObject(DB('student')).memoize();
findStudent('444-44-4444');
  • ๋‹จํ•ญ ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค๋ฉด ๋‹ค๋ฃจ๊ธฐ ์‰ฝ๊ณ  ํ•ฉ์„ฑํ•˜๊ธฐ๋„ ์‰ฌ์šธ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ํ”„๋กœ๊ทธ๋žจ์„ ๋” ์ž˜๊ฒŒ ๋ถ„ํ•ดํ•˜์—ฌ ์ „์ฒด๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์š”์†Œ๋ณ„๋กœ ๋ฉ”๋ชจํ™”ํ•˜๊ณ  ์บ์‹œ๋ฅผ ์ ์šฉํ•˜๋Š” ์ด์ ์„ ์‚ด๋ฆด ์ˆ˜ ์žˆ๋‹ค.

๐ŸŽˆ ๋ถ„ํ•ดํ•˜์—ฌ ๋ฉ”๋ชจํ™”๋ฅผ ๊ทน๋Œ€ํ™”โ€‹

  • ์ฝ”๋“œ๋ฅผ ์ž˜๊ฒŒ ๋‚˜๋ˆŒ์ˆ˜๋ก ๋ฉ”๋ชจํ™” ํšจ๊ณผ๋Š” ๋”์šฑ ์ปค์ง„๋‹ค.
  • ๋ฉ”๋ชจํ™”๊ฐ€ ์ผ์ข…์˜ ์ž‘์€ ์ฟผ๋ฆฌ ์บ์‹œ ์—ญํ• ์„ ๋‹ด๋‹นํ•˜๋ฉด์„œ ์ด๋ฏธ ์กฐํšŒํ•œ ๊ฐ์ฒด๋ฅผ ๋‹ค์Œ์— ๋นจ๋ฆฌ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ณด๊ด€ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค.
  • ํ•จ์ˆ˜๋ฅผ ์–ด๋–ค ๊ฐ’, ์ฆ‰ ๋Š๊ธ‹ํ•˜๊ฒŒ ๊ณ„์‚ฐ๋œ ๊ฐ’์œผ๋กœ ๋ฐ”๋ผ๋ณด๋Š” ๊ด€์ ์—์„œ ๋ฉ”๋ชจํ™”๋Š” ํ™•์‹คํžˆ ๊ทธ๋งŒํ•œ ๊ฐ€์น˜๊ฐ€ ์žˆ๋‹ค.
  • showStudent์— ์žˆ๋Š” ์ผ๋ถ€ ํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจ๋œ ํ•จ์ˆ˜๋กœ ๋ณ€๊ฒฝํ•œ ์ฝ”๋“œ๋‹ค.
const showStudent = R.compose(
map(append('#student-info')),
liftIO,
getOrElse('ํ•™์ƒ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค!'),
map(csv),
map(R.props(['ssn', 'firstname', 'lastname'])),
chain(findStudent),
chain(checkLengthSsn),
lift(cleanInput),
);

showStudent('444-44-4444').run(); // ํ‰๊ท  9.2 ๋ฐ€๋ฆฌ์ดˆ (๋ฉ”๋ชจํ™” X)
showStudent('444-44-4444').run(); // ํ‰๊ท  2.5 ๋ฐ€๋ฆฌ์ดˆ (๋ฉ”๋ชจํ™” O)

๐ŸŽˆ ์žฌ๊ท€ ํ˜ธ์ถœ์—๋„ ๋ฉ”๋ชจํ™”๋ฅผ ์ ์šฉโ€‹

  • ์žฌ๊ท€๋Š” ๋•Œ๋•Œ๋กœ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋ง์น˜๊ฒŒ ํ•œ๋‹ค. ์Šคํƒ์ด ๋น„์ •์ƒ์ ์œผ๋กœ ์ปค์งˆ ๋•Œ์ด๋‹ค.
  • ๋ฉ”๋ชจํ™”๋ฅผ ์ด์šฉํ•˜๋ฉด ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ๋•Œ๊ฐ€ ์žˆ๋‹ค.
  • ์ผ๋ฐ˜์ ์œผ๋กœ, ์žฌ๊ท€ ํ˜ธ์ถœ์€ ๊ธฐ์ € ์ผ€์ด์Šค์— ๋„๋‹ฌํ•  ๋•Œ๊นŒ์ง€ ๊ฐ™์€ ๋ฌธ์ œ,์ฆ‰ ํฐ ๋ฌธ์ œ์˜ ํ•˜์œ„ ๋ฌธ์ œ๋“ค์„ ํ’€์–ด, ๊ฒฐ๊ตญ ๋งˆ์ง€๋ง‰์— ์Šคํƒ์ด ํ’€๋ฆฌ๋ฉฐ ์ตœ์ข… ๊ฒฐ๊ณผ๋ฅผ ๋‚ธ๋‹ค.
  • ์ด๋•Œ ํ•˜์œ„ ๋ฌธ์ œ์˜ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œํ•˜๋ฉด ๊ฐ™์€ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์„ฑ๋Šฅ์„ ๋Œ์–ด์˜ฌ๋ฆด ์ˆ˜ ์žˆ๋‹ค.
3! = 3 * 2 * 1 = 6
// 4! = 4 x 3! ์ฒ˜๋Ÿผ ๊ณ„์Šน๋„ ๋” ์ž‘์€ ๊ณ„์Šน์œผ๋กœ ์žฌ๊ท€์  ํ‘œํ˜„์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
4! = 4 * 3 * 2 * 1 = 4 * 3! = 24
  • ๋”ฐ๋ผ์„œ ๊ณ„์Šน์„ ๊ณ„์‚ฐํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์€ ๋ฉ”๋ชจํ™”ํ•œ ์žฌ๊ท€ ํ˜ธ์ถœ ํ˜•ํƒœ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
const factorial = ((n) => (n === 0) ? 1
: (n * factorial(n - 1))).memoize();

factorial(100); // .299๋ฐ€๋ฆฌ์ดˆ
factorial(101); // .021๋ฐ€๋ฆฌ์ดˆ
  • ๊ณ„์Šน์˜ ์ˆ˜ํ•™์  ์›๋ฆฌ๋ฅผ ๋ฉ”๋ชจํ™” ํ˜•ํƒœ๋กœ ์‘์šฉํ•  ์ˆ˜ ์žˆ์–ด ๋‘ ๋ฒˆ์งธ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ์ฒ˜๋ฆฌ์œจ(throughput)์ด ํ™• ์˜ฌ๋ผ๊ฐ„๋‹ค.
  • ์Šคํƒ ํ”„๋ ˆ์ž„์„ ๊ด€๋ฆฌํ•˜๊ณ  ์Šคํƒ ์˜ค์—ผ์„ ๋ฐฉ์ง€ํ•˜๋Š” ํšจ๊ณผ๋„ ์žˆ๋‹ค.
  • ์ฒ˜์Œ factorial(100)์„ ์‹คํ–‰ํ•˜๋ฉด ์ „์ฒด ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‹คํ–‰ํ•˜๋ฉด 100๊ฐœ์˜ ํ”„๋ ˆ์ž„์„ ํ•จ์ˆ˜ ์Šคํƒ์— ์Œ“๋Š”๋‹ค. ์ด๊ฒƒ์ด ์žฌ๊ท€ ํ•ด๋ฒ•์˜ ํ ์ด๋‹ค.
  • ๊ณ„์Šน์„ ๊ณ„์‚ฐํ•˜๋Š” ์ผ์ฒ˜๋Ÿผ ์ฃผ์–ด์ง„ ์ž…๋ ฅ ์ˆซ์ž๋งŒํผ ํ”„๋ ˆ์ž„ ๊ฐœ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚  ์ˆ˜๋ฐ–์— ์—†๋Š” ๊ฒฝ์šฐ, ์žฌ๊ท€๋Š” ์Šคํƒ ๊ณต๊ฐ„์„ ๋„ˆ๋ฌด ๋งŽ์ด ํ—ˆ๋น„ํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ๋ฉ”๋ชจํ™”๋ฅผ ์ด์šฉํ•˜๋ฉด ๋‹ค์Œ ์ˆซ์ž๋ฅผ ๊ณ„์‚ฐํ•  ๋•Œ ํ•„์š”ํ•œ ์Šคํƒ ํ”„๋ ˆ์ž„ ๊ฐœ์ˆ˜๋ฅผ ์—„์ฒญ๋‚˜๊ฒŒ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“š ์žฌ๊ท€์™€ ๊ผฌ๋ฆฌ ํ˜ธ์ถœ ์ตœ์ ํ™”โ€‹

  • ์žฌ๊ท€ ํ˜ธ์ถœํ•  ๋•Œ ๋ฉ”๋ชจํ™”๋„ ๋ณ„ ๋„์›€์ด ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ํ•จ์ˆ˜ ์ž…๋ ฅ์ด ๊ณ„์† ๋ฐ”๋€” ์ˆ˜๋ฐ–์— ์—†์–ด ๋‚ด๋ถ€ ์บ์‹œ ๊ณ„์ธต์ด ์ œ ์ž„๋ฌด๋ฅผ ์ˆ˜ํ–‰ํ•  ๊ธฐํšŒ์กฐ์ฐจ ์—†๋‹ค๋ฉด ๊ทธ๋ ‡๋‹ค.
  • ๊ทธ๋ ‡๋‹ค๋ฉด ์žฌ๊ท€๋ฅผ ์ผ๋ฐ˜ ๋ฃจํ”„๋งŒํผ ์‹คํ–‰์„ ์ตœ์ ํ™”ํ•  ๋ฐฉ๋ฒ•์€ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋Œ€์‹  ๊ผฌ๋ฆฌ ์žฌ๊ท€ ํ˜ธ์ถœ(tail call optimization, TCO) ์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ๋” ์žฌ๊ท€ ํ˜ธ์ถœ์„ ์งœ๋ฉด ๋œ๋‹ค.
  • ์•ž์—์„œ ์žฌ๊ท€์ ์ธ ๊ณ„์Šน ํ•จ์ˆ˜๋ฅผ ๊ผฌ๋ฆฌ ์œ„์น˜์—์„œ ์žฌ๊ท€ํ•˜๋„๋ก ๋ฐ”๊พผ๋‹ค.
const factorial = (n, current = 1) => 
(n === 1) ? current
// ํ•จ์ˆ˜์˜ ๋งˆ์ง€๋ง‰ ๊ตฌ๋ฌธ์—์„œ ์žฌ๊ท€ ๋‹จ๊ณ„๋ฅผ ๋ฐŸ๋Š”๋‹ค.
: factorial(n - 1, n * current);
  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ช…๋ นํ˜• ๋ฒ„์ „๋งŒํผ ์‹ ์†ํ•˜๊ฒŒ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • TCO๋Š” **๊ผฌ๋ฆฌ ํ˜ธ์ถœ ์ œ๊ฑฐ(tail call elimination)**๋ผ๊ณ ๋„ ํ•˜๋Š”๋ฐ, ES6๋ถ€ํ„ฐ ์‹ ์„ค๋œ ์ปดํŒŒ์ผ๋Ÿฌ ๊ฐœ์„  ํ•ญ๋ชฉ์œผ๋กœ์„œ, ์žฌ๊ท€ ํ˜ธ์ถœ ์‹คํ–‰์„ ๋‹จ์ผ ํ”„๋ ˆ์ž„์œผ๋กœ ๋ˆŒ๋Ÿฌ ํŽด ์‹คํ–‰ํ•œ๋‹ค.
  • ๋ฌผ๋ก  ์žฌ๊ท€ ํ”„๋กœ๊ทธ๋žจ์ด ์ œ์ผ ๋งˆ์ง€๋ง‰์— ๋‹ค๋ฅธ ํ•จ์ˆ˜(๋ณดํ†ต ์ž๊ธฐ ์ž์‹ )๋ฅผ ํ˜ธ์ถœํ•  ๊ฒฝ์šฐ์—๋งŒ TCO๊ฐ€ ์ผ์–ด๋‚œ๋‹ค. ์ด๋•Œ ๋งˆ์ง€๋ง‰ ํ˜ธ์ถœ์ด ๊ผฌ๋ฆฌ ์œ„์น˜์— ์žˆ๋‹ค๊ณ  ๋ถ€๋ฅธ๋‹ค.
  • ์ด๋ ‡๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ์ตœ์ ์ผ๊นŒ??
  • ์žฌ๊ท€ ํ•จ์ˆ˜๊ฐ€ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋Ÿฐํƒ€์ž„์€ ๋‚จ์€ ํ•  ์ผ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋” ์ด์ƒ ํ˜„์žฌ ์Šคํƒ ํ”„๋ ˆ์ž„์„ ๋ถ™๋“ค๊ณ  ์žˆ์„ ์ด์œ ๊ฐ€ ์—†๊ณ  ๋”ฐ๋ผ์„œ ๊ทธ๋Œ€๋กœ ํ๊ธฐํ•œ๋‹ค.
  • ํ•จ์ˆ˜ ์ฝ˜ํ…์ŠคํŠธ์—์„œ ํ•„์š”ํ•œ ์ƒํƒœ ๊ฐ’์€ ๋Œ€๋ถ€๋ถ„ ์ธ์ˆ˜ ํ˜•ํƒœ๋กœ ๋‹ค์Œ ํ•จ์ˆ˜์— ๋„˜๊ธฐ๋ฉด ๋œ๋‹ค.
  • ์ด๋Ÿฌ๋ฉด ์žฌ๊ท€๋ฅผ ๋ฐ˜๋ณตํ•  ๋•Œ๋งˆ๋‹ค ์Šคํƒ์— ์ƒˆ ํ”„๋ ˆ์ž„์ด ๊ณ„์† ์Œ“์ด์ง€ ์•Š๊ณ  ์ด์ „์— ์“ฐ๊ณ  ๋ฒ„๋ฆฐ ํ”„๋ ˆ์ž„์„ ์žฌํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๐ŸŽˆ ๋น„๊ผฌ๋ฆฌ ํ˜ธ์ถœ์„ ๊ผฌ๋ฆฌ ํ˜ธ์ถœ๋กœ ์ „ํ™˜โ€‹

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ TCO ์ฒด์ œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ณ„์Šน ํ•จ์ˆ˜๋ฅผ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.
// ์ดˆ๊ธฐ ๋ฒ„์ „์˜ ์žฌ๊ท€ ํ•จ์ˆ˜
const factorial = (n) =>
(n === 1) ? 1
: (n * factorial(n - 1));
  • ์žฌ๊ท€ ๋‹จ๊ณ„ n * factorial(n -1) ๊ฐ’๊ณผ ์ˆซ์ž n์„ ๊ณฑํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋งˆ์ง€๋ง‰์— ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ๊ผฌ๋ฆฌ ํ˜ธ์ถœ์ด ์•„๋‹ˆ๋‹ค.
  • TCO ๋•์„ ๋ณด๋ ค๋ฉด ์ด ๋ถ€๋ถ„์„ ์žฌ๊ท€ ๋‹จ๊ณ„๋กœ ๋ฐ”๊ฟ”์•ผ ๋Ÿฐํƒ€์ž„์ด ์•Œ์•„์„œ ๊ณ„์Šน์„ ๋ฃจํ”„๋กœ ์ „ํ™˜ํ•  ๊ฒƒ์ด๋‹ค. ์ „ํ™˜ ๊ณผ์ •์€ ๋‘ ๋‹จ๊ณ„๋กœ ๋‚˜๋‰œ๋‹ค.
    1. ๊ณฑ์…ˆ ๋ถ€๋ถ„์„ ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ถ”๊ฐ€ํ•ด์„œ ํ˜„์žฌ ๊ณฑ์…ˆ์„ ์ถ”์ ํ•œ๋‹ค.
    2. ES6 ๊ธฐ๋ณธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๊ธฐ๋ณธ ์ธ์ˆ˜ ๊ฐ’์„ ๋ฏธ๋ฆฌ ์ •ํ•œ๋‹ค.
    const factorial = (n, current = 1) =>
    (n === 1) ? current
    : factorial(n - 1, n * current);
  • ๊ผฌ๋ฆฌ ์žฌ๊ท€ ํ•จ์ˆ˜๊ฐ€ ์ผ๋ฐ˜ ๋ฃจํ”„์— ํ”ํ•œ ํŠน์„ฑ์„ ๊ฐ–๊ณ  ์žˆ๊ธฐ์— ์ด๋Ÿฌํ•œ ์ „ํ™˜์ด ๊ฐ€๋Šฅํ•œ ๊ฒƒ์ด๋‹ค.
  • ๋‹ค์Œ ์˜ˆ๋Š” ๋ฐฐ์—ด ์›์†Œ๋ฅผ ์ „๋ถ€ ๋”ํ•˜๋Š” ์žฌ๊ท€ ์ฝ”๋“œ์ด๋‹ค.
function sum(arr) {
if(_.isEmpty(arr)) {
return 0;
}
return _.first(arr) + sum(_.rest(arr));
}
  • ํ•จ์ˆ˜๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ทจํ•˜๋Š” ํ–‰์œ„, ์ฆ‰, _.first(arr) + sum(_.rest(arr))์€ ๊ผฌ๋ฆฌ ํ˜ธ์ถœ์ด ์•„๋‹ˆ๋‹ค.
  • ํ›„์† ํ˜ธ์ถœ๊ณผ ๊ณต์œ ํ•  ๋ฐ์ดํ„ฐ๋Š” ํ•จ์ˆ˜ ์ธ์ˆ˜์˜ ์ผ๋ถ€๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค.
function sum(arr, acc = 0) {
if(_.isEmpty(arr)) {
return acc;
}
return sum(_.rest(arr), acc + _.first(arr));
}
  • ์—ฌ๊ธฐ์„œ ์œ ์˜ํ•  ์ ์€, TCO๊ฐ€ ES4 ์‹œ์ ˆ ์ฒ˜์Œ ์ดˆ์•ˆ์ด ๋‚˜์˜จ ์ดํ›„ ์ง€๊ธˆ์€ ์‚ฌ์‹ค์ƒ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ‘œ์ค€์ด ๋˜์—ˆ์ง€๋งŒ ์•„์ง ์ด๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋” ๋งŽ๋‹ค. (๊ทธ๋ž˜์„œ ๋ฐ”๋ฒจ๊ณผ ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ๋ฅผ ์‚ฌ์šฉ)

๐Ÿ“š ๋งˆ์น˜๋ฉฐโ€‹

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