Pure functions in JavaScript1 - Lee-hyuna/33-js-concepts-kr GitHub Wiki

"pure" ν•¨μˆ˜λŠ” 무엇인가?

순수 ν•¨μˆ˜λŠ” κ·Έ λ²”μœ„λ₯Ό λ²—μ–΄λ‚˜λŠ” λ³€μˆ˜μ˜ μƒνƒœμ— μ˜μ‘΄ν•˜μ§€ μ•Šκ³  μˆ˜μ •ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
ꡬ체적으둜 λ§ν•˜μžλ©΄, 순수 ν•¨μˆ˜λŠ” λ™μΌν•œ 맀개 λ³€μˆ˜κ°€ 주어지면 항상 λ™μΌν•œ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•œλ‹€λŠ” μ˜λ―Έμž…λ‹ˆλ‹€.
싀행은 μ‹œμŠ€ν…œμ˜ μƒνƒœμ— μ˜μ‘΄ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
순수 ν•¨μˆ˜λŠ” ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ˜ κΈ°λ‘₯μž…λ‹ˆλ‹€.

예제

var values = { a: 1 }

function impureFunction(items) {
  var b = 1

  items.a = items.a * b + 2

  return items.a
}

var c = impureFunction(values)
// 이제 values.a λŠ” 3이고, λΆˆμˆœν•œ ν•¨μˆ˜λŠ” 그것을 μˆ˜μ •ν•©λ‹ˆλ‹€.

μ—¬κΈ°μ—μ„œλŠ” 주어진 객체의 속성을 μˆ˜μ •ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ―€λ‘œ μš°λ¦¬λŠ” ν•¨μˆ˜μ˜ λ²”μœ„λ₯Ό λ²—μ–΄λ‚˜λŠ” 객체λ₯Ό μˆ˜μ •ν•©λ‹ˆλ‹€ : ν•¨μˆ˜λŠ” λΆˆμˆœν•©λ‹ˆλ‹€.

var values = { a: 1 }

function pureFunction(a) {
  var b = 1

  a = a * b + 2

  return a
}

var c = pureFunction(values.a)
// values.a λŠ” μˆ˜μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. μ—¬μ „νžˆ 1μž…λ‹ˆλ‹€.

이제 μš°λ¦¬λŠ” λ‹¨μˆœνžˆ ν•¨μˆ˜μ˜ λ²”μœ„μ—μžˆλŠ” 맀개 λ³€μˆ˜λ₯Ό μˆ˜μ •ν•©λ‹ˆλ‹€. 아무것도 μ™ΈλΆ€μ—μ„œ μˆ˜μ •λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€!

var values = { a: 1 }
var b = 1

function impureFunction(a) {
  a = a * b + 2

  return a
}

var c = impureFunction(values.a)
// μ‹€μ œλ‘œ`c`의 값은`b`의 값에 달렀 μžˆμŠ΅λ‹ˆλ‹€.
// 더 큰 μ½”λ“œ λ² μ΄μŠ€μ—μ„œλŠ” κ²°κ³Όλ₯Ό μ•”μ‹œ 적으둜 λ³€ν™”μ‹œν‚¬ 수 있기 λ•Œλ¬Έμ—
// κ·Έ 점을 μžŠμ–΄ 버릴 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

μ—¬κΈ°μ„œ, bλŠ” ν•¨μˆ˜μ˜ λ²”μœ„μ— μ†ν•˜μ§€ μ•ŠλŠ”λ‹€. κ²°κ³ΌλŠ” 상황에 따라 λ‹¬λΌμ§‘λ‹ˆλ‹€: μ˜ˆμƒν•œ 놀라움!

var values = { a: 1 }
var b = 1

function pureFunction(a, c) {
  a = a * c + 2

  return a
}

var c = pureFunction(values.a, b)
// μ—¬κΈ°μ„œ c의 값은 b의 값에 μ˜μ‘΄ν•œλ‹€λŠ” 것을 λΆ„λͺ…νžˆν–ˆμŠ΅λ‹ˆλ‹€
// λ“± λ’€μ—μ„œ λΉ„μ—΄ν•œ 놀라움은 μ—†μ—ˆμŠ΅λ‹ˆλ‹€.

ꡬ체적으둜 μ–΄λ–»κ²Œ λ³΄μž…λ‹ˆκΉŒ?

이 μ½”λ“œκ°€ μ‘΄μž¬ν•œλ‹€κ³  μƒκ°ν•˜λ©΄ :

var getMinQuantity = function getMinQuantity(name) {
  // 주어진 이름과 κ΄€λ ¨ν•˜μ—¬ 숫자λ₯Ό λ°˜ν™˜ν•˜λŠ” μˆœμˆ˜ν•œ κΈ€κΌ΄.
}

λžŒλ‹€ ν”„λ‘œμ νŠΈμ— μ‘΄μž¬ν•  μˆ˜μžˆλŠ” λ‹€μŒ μ½”λ“œ 예제λ₯Ό λ³΄κ² μŠ΅λ‹ˆλ‹€.

var popover = {
  // A bunch of code…

  addQuantityText: function(quantity) {
    var quantityTextOptions = {
      namespace: 'quantity',
      initialChildIndex: 2,
      quantity: quantity,
    }

    try {
      this.formatQuantityText(quantityTextOptions)
    } catch (err) {
      console.log("Couldn't add quantity text!")
    }
  },

  formatQuantityText: function(options) {
    if (!this.$$boxContainer) {
      throw new Error('$$boxContainer is not configured')
    }

    var namespace = options.namespace || 'quantity'
    var quantity = options.quantity || 0
    var initialChildIndex = options.initialChildIndex || 0

    var $$quantity = new Canvas() // implementation details hidden
    $$quantity.name = namespace
    $$quantity.value = quantity
    this.setQuantityTextColor($$quantity)

    this.$$boxContainer.addChild($$quantity, initialChildIndex)

    return $$quantity
  },

  setQuantityTextColor: function($$quantity) {
    if (!$$quantity) return

    var minQuantity = getMinQuantity($$quantity.name)
    var quantity = $$quantity.value || minQuantity
    var hasEnoughQuantity = quantity >= minQuantity

    $$quantity.color = hasEnoughQuantity ? 'green' : 'red'
  },
}

λͺ¨λ‘ λΆˆμΆ©λΆ„ ν•œ addQuantityText(), formatQuantityText() 및 setQuantityTextColor()κ°€ μžˆμŠ΅λ‹ˆλ‹€.
우리의 λ§₯λ½μ—μ„œ addQuantityText()λŠ” $$ boxContainer에 "μˆ˜λŸ‰ ν‘œμ‹œ"λ₯Ό 원할 λ•Œ μ‹€μ œλ‘œ μ‚¬μš©λ˜λŠ” λ©”μ†Œλ“œμž…λ‹ˆλ‹€.
이것은 κ΅¬ν˜„ μ„ΈλΆ€ 사항을 λ‹€λ£¨λŠ” μ§„μž… μ μž…λ‹ˆλ‹€. $$ μˆ˜λŸ‰μ— λ¬Έμ œκ°€ 생길 λ•Œ 보물 찾기의 μ‹œμž‘μ΄ 될 κ°€λŠ₯μ„±μ΄μžˆλŠ” 이 방법을 μ‚΄νŽ΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.
-ν•˜μ§€λ§Œ μž¬λ―ΈμžˆλŠ” 것은 μ•„λ‹™λ‹ˆλ‹€.

그것이 μ“°μ—¬μ§€λŠ” 방식은 μž₯기적으둜 였λ₯˜κ°€ λ‚  수 μžˆμŠ΅λ‹ˆλ‹€.

볡작 해지면

이 μ˜ˆμ œμ—μ„œλŠ” ν•¨μˆ˜μ˜ μ‹€ν–‰ μˆœμ„œκ°€ μ€‘μš”ν•©λ‹ˆλ‹€.

κ·Έλƒ₯ 2 쀄을 λ°”κΎΈλ©΄ λͺ¨λ“  것을 망칠거야. 그것은 λͺ…λ°±ν•˜κ²Œ 듀릴지 λͺ¨λ₯΄μ§€λ§Œ λ””λ²„κΉ…ν•˜κΈ°κ°€ 훨씬 더 μ–΄λ ΅μŠ΅λ‹ˆλ‹€.

var popover = {
  // A bunch of code…

  addQuantityText: function(quantity) {
    var quantityTextOptions = {
      namespace: 'quantity',
      initialChildIndex: 2,
      quantity: quantity,
    }

    try {
      this.formatQuantityText(quantityTextOptions)
    } catch (err) {
      console.log("Couldn't add quantity text!")
    }
  },

  formatQuantityText: function(options) {
    if (!this.$$boxContainer) {
      throw new Error('$$boxContainer is not configured')
    }

    var namespace = options.namespace || 'quantity'
    var quantity = options.quantity || 0
    var initialChildIndex = options.initialChildIndex || 0

    var $$quantity = new Canvas() // implementation details hidden
    this.setQuantityTextColor($$quantity)
    $$quantity.name = namespace
    $$quantity.value = quantity

    return $$quantity
  },

  setQuantityTextColor: function($$quantity) {
    if (!$$quantity) return

    var minQuantity = getMinQuantity($$quantity.name)
    var quantity = $$quantity.value || minQuantity
    var hasEnoughQuantity = quantity >= minQuantity

    $$quantity.color = hasEnoughQuantity ? 'green' : 'red'
  },
}

이제 μ½”λ“œμ— 였λ₯˜κ°€ μžˆμŠ΅λ‹ˆλ‹€. λ¬Έμ œλŠ” κ°μ§€ν•˜κΈ° νž˜λ“  μΌμž…λ‹ˆλ‹€!
μ—¬κΈ°μ—μ„œ setQuantityTextColor()λŠ” $$ μˆ˜λŸ‰μ˜ 색상을 λ‹΄λ‹Ήν•©λ‹ˆλ‹€.
λ”°λΌμ„œ 객체λ₯Ό μˆ˜μ •ν•˜λŠ” λ§ˆμ§€λ§‰ 것을 μž‘μ•„λ‚΄λŠ” λ©”μ†Œλ“œλ₯Ό 탐색 ν•œ λ‹€μŒ, 전체 ν”Œλ‘œμš°λ₯Ό λ‹€μ‹œ κ΅¬μ„±ν•˜μ—¬ 잘λͺ»λœ 점을 μ΄ν•΄ν•΄μ•Όν•©λ‹ˆλ‹€.
이 μ‹œμ μ—μ„œ formatQuantityText()λ₯Ό μž‘μ€ λ©”μ†Œλ“œλ‘œ λΆ„ν•΄ν•˜μ—¬ κ΅¬ν˜„ μ„ΈλΆ€ 사항을 λ‹¨μˆœν™” ν•œ 것을 ν›„νšŒν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.
일반적으둜 디버깅 ν•  λ•Œ κ³ λ €ν•΄μ•Ό ν•  λ§Žμ€ μ½”λ“œκ°€ μžˆμŠ΅λ‹ˆλ‹€.
큰 λ©”μ†Œλ“œλ₯Ό μž‘μ€ λ©”μ†Œλ“œλ‘œ λΆ„ν• ν•˜λŠ” 것이 디버그λ₯Ό μ–΄λ ΅κ²Œ λ§Œλ“ λ‹€λ©΄ μˆœμˆ˜ν•œ ν•¨μˆ˜μ˜ κ°œλ…μ΄ μ€‘μš” 해지고 μžˆλ‹€κ³  μƒκ°ν•˜λ©΄λ©λ‹ˆλ‹€.

μˆœμˆ˜ν•œ ν•¨μˆ˜λ‘œ ν•΄λ³΄μž.

μ½”λ“œλ₯Ό λ‹€μ‹œ μž‘μ„±ν•˜κΈ° μœ„ν•΄ μ΅œλŒ€μ˜ 순수 ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

var popover = {
  // μ‹œμŠ€ν…œ μƒνƒœμ˜ λͺ¨λ“  μˆ˜μ • 사항이 여기에 κ·Έλ£Ήν™”λ©λ‹ˆλ‹€.
  // 이 μœ μΌν•œ 방법은 디버그λ₯Ό λ‹¨μˆœν™”ν•˜κ³  λΆ€μž‘μš©μ„ μ΅œμ†Œν™”ν•˜λŠ” μš”μ†Œ μ‚½μž…μ„ λ‹΄λ‹Ήν•©λ‹ˆλ‹€.  

  addQuantityText: function(quantity) {
    if (!this.$$boxContainer) {
      throw new Error('$$boxContainer is not configured')
    }

    var quantityTextOptions = {
      namespace: 'quantity',
      quantity: quantity,
    }
    var $$quantity = this.formatQuantityText(quantityTextOptions)

    this.$$boxContainer.addChild($$quantity, 2)
  },

  // 이 λ°©λ²•μ—λŠ” λΆ€μž‘μš©μ΄ μ—†μŠ΅λ‹ˆλ‹€.
  // κ·Έλƒ₯ λ‹€λ₯Έ 순수 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€. μ›ν•˜λŠ”λŒ€λ‘œ μΊ”λ²„μŠ€ 객체λ₯Ό μƒμ„±ν•˜κ³  λ°˜ν™˜ν•©λ‹ˆλ‹€.

  formatQuantityText: function(options) {
    var namespace = options.namespace || 'quantity'
    var quantity = options.quantity || 0

    var $$quantity = new Canvas() // implementation details hidden
    $$quantity.name = namespace
    $$quantity.value = quantity
    $$quantity.color = this.getQuantityTextColor(quantity, namespace)

    return $$quantity
  },

  // 이 λ°©λ²•μ—λŠ” λΆ€μž‘μš©μ΄ μ—†μŠ΅λ‹ˆλ‹€.
  // 주어진 μˆ˜λŸ‰κ³Ό κ΄€λ ¨ν•˜μ—¬ μ •ν™•ν•œ 색상을 λ°˜ν™˜ν•©λ‹ˆλ‹€.
  getQuantityTextColor: function(quantity, namespace) {
    var minQuantity = getMinQuantity(namespace)
    var hasEnoughQuantity = quantity && quantity >= minQuantity

    return hasEnoughQuantity ? 'green' : 'red'
  },

}

이 μƒˆλ‘œμš΄ λ²„μ „μ—λŠ” 근본적인 λ³€ν™”κ°€ μ—†μŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λ¬΄μ‹œν•  μˆ˜μ—†λŠ” 이점이 μžˆμŠ΅λ‹ˆλ‹€.

μš°λ¦¬κ°€ μ—¬κΈ°μ„œ ν•œ 일은 :

  • setQuantityTextColor() λŒ€μ‹  getQuantityTextColor()
  • 이 λ©”μ†Œλ“œλŠ” 이전에 ν–ˆλ˜ κ²ƒμ²˜λŸΌ 객체λ₯Ό 직접 μˆ˜μ •ν•˜λŠ” λŒ€μ‹ μ— μš°λ¦¬κ°€ 제곡 ν•œ 것과 κ΄€λ ¨λœ 색상을 λ°˜ν™˜ν•©λ‹ˆλ‹€.
  • λ©”μ„œλ“œλŠ” λ³€μˆ˜λ₯Ό ν•΄λ‹Ή λ²”μœ„ λ°–μœΌλ‘œ κ°„μ£Όν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
  • λ©”μ„œλ“œλŠ” μˆœμˆ˜ν•œ λ©”μ„œλ“œλ§Œ ν˜ΈμΆœν•©λ‹ˆλ‹€.
  • formatQuantityText()μ—μ„œ $$ μˆ˜λŸ‰ 객체의 생성 / μˆ˜μ •μ„ λΆ„λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€.
  • addQuantityText()μ—μ„œ μ‹œμŠ€ν…œ μƒνƒœμ˜ μˆ˜μ •μ„ κ²©λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€.

κ·Έλ ‡κ²Œν•¨μœΌλ‘œμ¨ λΆ€μž‘μš©μ΄μžˆλŠ” λ©”μ†Œλ“œλ₯Ό μ œκ±°ν–ˆμŠ΅λ‹ˆλ‹€. μ½”λ“œ μœ μ§€ 관리가 간단해 μ‘ŒμŠ΅λ‹ˆλ‹€.
$$ μˆ˜λŸ‰μœΌλ‘œ λ¬Έμ œκ°€ λ°œμƒν•˜λ©΄ 찾을 방법은 ν•˜λ‚˜λΏμž…λ‹ˆλ‹€.

μΈν„°νŽ˜μ΄μŠ€ κ°„μ†Œν™”

μš°λ¦¬λŠ” μ—¬κΈ° 곡개 방법을 μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€. λΉ„κ³΅κ°œλ‘œ λ§Œλ“€λ©΄ μ™„μ „νžˆ 적합 ν•  κ²ƒμž…λ‹ˆλ‹€.

사싀, 우리의 역할은 μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ‹¨μˆœν™”ν•˜λŠ” 것이기 λ•Œλ¬Έμ— API와 관련이 μ—†μŠ΅λ‹ˆλ‹€.
Backbone.jsλ₯Ό μ‚¬μš©ν•˜μ—¬ 개인적인 λ°©λ²•μœΌλ‘œ λ‚΄ κ²Œμ‹œλ¬Όμ„ μ‚΄νŽ΄λ³΄μ‹­μ‹œμ˜€.

그듀이 μˆœμˆ˜ν•œ κ²ƒμ²˜λŸΌ, νŠΉμ • 상황에 μ˜μ‘΄ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μΆ”μΆœν•˜κΈ°κ°€ μ‰½μŠ΅λ‹ˆλ‹€!

function getQuantityTextColor(quantity, namespace) {
  var minQuantity = getMinQuantity(namespace)
  var hasEnoughQuantity = quantity && quantity >= minQuantity

  return hasEnoughQuantity ? 'green' : 'red'
}

function formatQuantityText(options) {
  var namespace = options.namespace || 'quantity'
  var quantity = options.quantity || 0

  var $$quantity = new Canvas() // implementation details hidden
  $$quantity.name = namespace
  $$quantity.value = quantity
  $$quantity.color = getQuantityTextColor(quantity, namespace)

  return $$quantity
}

그리고 λ‚˜μ„œ μ½”λ“œμ—μ„œ λ‚˜μ€‘μ— :

var popover = {
  // A bunch of code…

  addQuantityText: function(quantity) {
    if (!this.$$boxContainer) {
      throw new Error('$$boxContainer is not configured')
    }

    var quantityTextOptions = {
      namespace: 'quantity',
      quantity: quantity,
    }
    var $$quantity = formatQuantityText(quantityTextOptions)

    this.$$boxContainer.addChild($$quantity, 2)
  },

  // A bunch of code…
}

순수 ν•¨μˆ˜μ˜ μž₯점

순수 ν•¨μˆ˜μ˜ κ°€μž₯ 큰 μž₯점은 λΆ€μž‘μš©μ΄ μ—†λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. ν•΄λ‹Ή λ²”μœ„λ₯Ό λ²—μ–΄λ‚œ μ‹œμŠ€ν…œ μƒνƒœλŠ” μˆ˜μ •ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
그런 λ‹€μŒ μ½”λ“œλ₯Ό λ‹¨μˆœν™”ν•˜κ³  λͺ…ν™•νžˆν•©λ‹ˆλ‹€. μˆœμˆ˜ν•œ ν•¨μˆ˜λ₯Ό 호좜 ν•  λ•ŒλŠ” λ‹€λ₯Έ κ³³μ—μ„œ 아무것도 λΆ€λŸ¬λœ¨λ¦¬μ§€ μ•Šμ•˜λ‹€λŠ” 것을 μ•ŒκΈ° λ•Œλ¬Έμ—
λ°˜ν™˜ 값에 μ§‘μ€‘ν•΄μ•Όν•©λ‹ˆλ‹€.

순수 ν•¨μˆ˜λ„ κ°•λ ₯ν•©λ‹ˆλ‹€. κ·Έ μ‹€ν–‰ μˆœμ„œλŠ” μ‹œμŠ€ν…œμ— μ•„λ¬΄λŸ° 영ν–₯을주지 μ•ŠμŠ΅λ‹ˆλ‹€. 순수 ν•¨μˆ˜λ‘œ 연산을 병렬화 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ˜ν•œ κ³ λ €ν•΄μ•Ό ν•  λ¬Έλ§₯이 μ—†μœΌλ―€λ‘œ 순수 ν•¨μˆ˜λ₯Ό λ‹¨μœ„ ν…ŒμŠ€νŠΈν•˜λŠ” 것이 맀우 μ‰½μŠ΅λ‹ˆλ‹€. κ·Έλƒ₯ μž… / 좜λ ₯에 μ§‘μ€‘ν•˜μ‹­μ‹œμ˜€.

λ§ˆμ§€λ§‰μœΌλ‘œ, μˆœμˆ˜ν•œ ν•¨μˆ˜μ˜ μ‚¬μš©μ„ μ΅œλŒ€ν™”ν•˜λ©΄ μ½”λ“œκ°€λ³΄λ‹€ κ°„λ‹¨ν•˜κ³  μœ μ—° ν•΄μ§‘λ‹ˆλ‹€.

λ””μžμΈμ˜ 문제

μ‹€μ œλ‘œ 객체 지ν–₯ μ½”λ“œλ₯Ό μˆ˜ν–‰ ν•  λ•Œ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ° κ°œλ…μ΄ μ ν•©ν•˜μ§€ μ•Šλ‹€κ³  생각할 수 μžˆμŠ΅λ‹ˆλ‹€.
OOP와 FPλŠ” μ ˆλŒ€μ μœΌλ‘œ ν˜Έν™˜λ˜κΈ° λ•Œλ¬Έμ— 이것은 잘λͺ»λœ κ²ƒμž…λ‹ˆλ‹€!

μ‹€μ œλ‘œ 여기에 λ‚˜μ˜¨ μ•„μ΄λ””μ–΄λŠ” κ°„λ‹¨ν•©λ‹ˆλ‹€. μ‹œμŠ€ν…œμ— 영ν–₯을 λ―ΈμΉ˜λŠ” ν•¨μˆ˜μ˜ 수λ₯Ό μ œν•œν•˜μ—¬ μ½”λ“œλ₯Ό λ‹¨μˆœν™”ν•˜μ‹­μ‹œμ˜€.

μ½”λ“œμ—μ„œ μˆœμˆ˜ν•œ ν•¨μˆ˜μ˜ 수λ₯Ό μ΅œλŒ€ν™”ν•˜κΈ° μœ„ν•΄ 두 번 μƒκ°ν•˜λ„λ‘ κ°•μš”ν•˜λ©΄ μœ μ§€ 보수 / 수λͺ… / 디버그λ₯Ό 더 μ‰½κ²Œ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€!

κΈ€μŽ„, 당신은 κ·Έ 생각을 κ°€μ§€κ³ μžˆλ‹€. μ‹€μ œλ‘œλŠ” λ””μžμΈμ˜ 문제이며, 예λ₯Ό λ“€μ–΄ getκ³Ό set μ‚¬μ΄μ˜ μ„ νƒμž…λ‹ˆλ‹€.