πŸ“’

Closure

closure

ν•¨μˆ˜μ™€ ν•¨μˆ˜κ°€ μ„ μ–Έλœ μ–΄νœ˜μ (lexical) ν™˜κ²½μ˜ μ‘°ν•©
μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜λŠ” ν™˜κ²½κ³Ό λ³„κ°œλ‘œ, 기쑴에 μ„ μ–Έλ˜μ–΄ 있던 ν™˜κ²½ - μ–΄νœ˜μ  ν™˜κ²½ - 을 κΈ°μ€€μœΌλ‘œ λ³€μˆ˜λ₯Ό μ‘°νšŒν•œλ‹€.
κ°„λ‹¨νžˆ λ§ν•˜λ©΄ μ™ΈλΆ€ ν•¨μˆ˜μ˜ μ»¨ν…μŠ€νŠΈμ— μ ‘κ·Όν•  수 μžˆλŠ” λ‚΄λΆ€ ν•¨μˆ˜λ₯Ό ν΄λ‘œμ €λΌκ³  함!
ν•¨μˆ˜ μ„ μ–Έλ¬ΈμœΌλ‘œ μ„ μ–Έν•œ ν•¨μˆ˜λŠ” 일반 λ³€μˆ˜μ™€λŠ” 달리 λ°”λ‘œ μ΄ˆκΈ°ν™”κ°€ λœλ‹€.
μ™ΈλΆ€ν•¨μˆ˜μ˜ 싀행이 μ’…λ£Œλœ 후에도, ν΄λ‘œμ € ν•¨μˆ˜λŠ” μ™ΈλΆ€ν•¨μˆ˜μ˜ μŠ€μ½”ν”„, 즉, ν•¨μˆ˜κ°€ μ„ μ–Έλœ μ–΄νœ˜μ  ν™˜κ²½μ— μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.
ν΄λ‘œμ € μ‚¬μš© μ˜ˆμ‹œ: ν΄λ‘œμ €λ₯Ό 톡해 컀링(currying, ν•¨μˆ˜ ν•˜λ‚˜κ°€ n개의 인자λ₯Ό λ°›λŠ” λŒ€μ‹  n개의 ν•¨μˆ˜λ₯Ό λ§Œλ“€μ–΄ 각각 인자λ₯Ό λ°›κ²Œ ν•˜λŠ” 방법), ν΄λ‘œμ € λͺ¨λ“ˆ(λ³€μˆ˜λ₯Ό μ™ΈλΆ€ ν•¨μˆ˜ μŠ€μ½”ν”„ μ•ˆμͺ½μ— 감좔어, λ³€μˆ˜κ°€ ν•¨μˆ˜ λ°–μ—μ„œ λ…ΈμΆœλ˜λŠ” 것을 λ§‰λŠ” 방법)

νŠΉμ§•

scope ν•¨μˆ˜λŠ” 두가지 νŠΉμ§•μ„ λ§Œμ‘±ν•΄μ•Όν•œλ‹€.

ν•¨μˆ˜λ₯Ό λ¦¬ν„΄ν•˜λŠ” ν•¨μˆ˜

const adder = function (x) { return function (y) { return x + y; } }
JavaScript
볡사
리턴값이 ν•¨μˆ˜μ˜ ν˜•νƒœμ΄λ‹€.

λ‚΄λΆ€ ν•¨μˆ˜μ™€ μ™ΈλΆ€ ν•¨μˆ˜

λ¦¬ν„΄ν•˜λŠ” ν•¨μˆ˜μ— μ˜ν•΄ μŠ€μ½”ν”„κ°€ κ΅¬λΆ„λ˜λ―€λ‘œ λ‚΄λΆ€ ν•¨μˆ˜λŠ” μ™ΈλΆ€ ν•¨μˆ˜μ— μ„ μ–Έλœ λ³€μˆ˜μ— 접근이 κ°€λŠ₯ν•˜λ‹€.
μ™ΈλΆ€ ν•¨μˆ˜λŠ” μ•ˆμͺ½ μŠ€μ½”ν”„μ—μ„œ μ„ μ–Έλœ λ³€μˆ˜μ— 접근이 λΆˆκ°€λŠ₯ν•˜κ³  λ‚΄λΆ€ ν•¨μˆ˜μ—μ„œλŠ” λ°”κΉ₯ μŠ€μ½”ν”„μ—μ„œ μ„ μ–Έλœ λ³€μˆ˜μ— 접근이 κ°€λŠ₯ν•˜λ‹€

closure ν•¨μˆ˜μ˜ μž₯점

데이터λ₯Ό λ³΄μ‘΄ν•˜λŠ” ν•¨μˆ˜

μ™ΈλΆ€ν•¨μˆ˜μ˜ 싀행이 λλ‚˜λ”λΌλ„ μ™ΈλΆ€ ν•¨μˆ˜ λ‚΄ λ³€μˆ˜λ₯Ό μ‚¬μš©ν•  수 있음
일반적인 ν•¨μˆ˜λŠ” ν•¨μˆ˜ 싀행이 λλ‚œ ν›„ ν•¨μˆ˜ λ‚΄λΆ€μ˜ λ³€μˆ˜λ₯Ό μ‚¬μš©ν•  수 μ—†λ‹€ ν•˜μ§€λ§Œ ν΄λ‘œμ € ν•¨μˆ˜λŠ” μ™ΈλΆ€ ν•¨μˆ˜μ˜ 싀해이 λλ‚˜λ”λΌλ„ μ™ΈλΆ€ ν•¨μˆ˜ λ‚΄ λ³€μˆ˜κ°€ λ©”λͺ¨λ¦¬ 상에 μ €μž₯λœλ‹€.
이처럼 νŠΉμ • 데이터λ₯Ό μŠ€μ½”ν”„ μ•ˆμ— 가두어 λ‘” μ±„λ‘œ 계속 μ‚¬μš©ν•  수 μžˆλ‹€
const adder = function (x) { return function (y) { return x + y; } } const add5 = adder(5); add5(7); // 12 add5(10); // 15
JavaScript
볡사
ν΄λ‘œμ € ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•œ HTML λ¬Έμžμ—΄ 생성기 λ§Œλ“€κΈ°
const tagMaker = tag => content => `<${tag}>${content}</${tag}>` const divMaker = tagMaker('div'); divMaker('hello'); // '<div>hello</div>' const anchorMaker = tagMaker('a'); anchorMaker('go'); // '<a>go</a>';
JavaScript
볡사

μ •λ³΄μ˜ μ ‘κ·Ό μ œν•œ

const makeCounter = () => { let value = 0; return { increase: () => { value = value + 1 }, decrease: () => { value = value - 1 }, getValue: () => value } } const counter1 = makeCounter(); counter1 // {increase: f, decrease: f, getValue: f}
JavaScript
볡사
ν΄λ‘œμ €λ₯Ό μ΄μš©ν•΄ λ‚΄λΆ€ ν•¨μˆ˜λ₯Ό 객체에 λ‹΄μ•„μ„œ μ—¬λŸ¬ 개의 λ‚΄λΆ€ ν•¨μˆ˜λ₯Ό λ¦¬ν„΄ν•˜λ„λ‘ λ§Œλ“ λ‹€.
μ™ΈλΆ€ μŠ€μ½”ν”„μ—μ„œ λ‚΄λΆ€ μŠ€μ½”ν”„μ˜ λ³€μˆ˜μ— μ ‘κ·Όν•  수 μ—†μœΌλ―€λ‘œ μš°λ¦¬λŠ” makeCounterλ₯Ό 바꾸지 μ•Šκ³  내뢀에 μ„ μ–Έλœ value에 μƒˆλ‘œμš΄ 값을 ν• λ‹Ήν•  수 μ—†λ‹€.
β‡’ 이것을 μΊ‘μŠν™”(μ •λ³΄μ˜ μ ‘κ·Ό μ œν•œ) 라고 ν•œλ‹€.
side effect에 λ”°λ₯Έ 였λ₯˜λ‘œλΆ€ν„° 데이터λ₯Ό μ•ˆμ „ν•˜κ²Œ λ³΄ν˜Έν•  수 μžˆλ‹€.
ν΄λ‘œμ €λ₯Ό 톡해 λΆˆν•„μš”ν•œ μ „μ—­ λ³€μˆ˜ μ‚¬μš©μ„ 쀄이고, μŠ€μ½”ν”„λ₯Ό μ΄μš©ν•΄ 값을 보닀 μ•ˆμ „ν•˜κ²Œ λ‹€λ£° 수 μžˆλ‹€.

λͺ¨λ“ˆν™”

ν•¨μˆ˜ μž¬μ‚¬μš©μ„±μ„ κ·ΉλŒ€ν™”ν•˜μ—¬ ν•¨μˆ˜ ν•˜λ‚˜λ₯Ό μ™„μ „νžˆ 독립적인 λΆ€ν’ˆ ν˜•νƒœλ‘œ 뢄리
const counter1 = makeCounter() const counter2 = makeCouter()
JavaScript
볡사
두 counterλŠ” λ…λ¦½μ μœΌλ‘œ λŒμ•„κ°„λ‹€.
ν΄λ‘œμ €λŠ” λͺ¨λ“ˆν™”에 μœ λ¦¬ν•˜λ‹€.

closure ν•¨μˆ˜μ˜ 단점

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” 가비지 μ»¬λ ‰μ…˜μ„ 톡해 λ©”λͺ¨λ¦¬ 관리λ₯Ό ν•©λ‹ˆλ‹€. 객체가 μ°Έμ‘° λŒ€μƒμ΄ 아닐 λ•Œ, 가비지 μ»¬λ ‰μ…˜μ— μ˜ν•΄ μžλ™μœΌλ‘œ λ©”λͺ¨λ¦¬ 할당이 ν•΄μ œλ©λ‹ˆλ‹€. 일반 ν•¨μˆ˜μ˜€λ‹€λ©΄ ν•¨μˆ˜ μ‹€ν–‰ μ’…λ£Œ ν›„ 가비지 μ»¬λ ‰μ…˜(μ°Έκ³  자료: MDN 'μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ λ©”λͺ¨λ¦¬ 관리') λŒ€μƒμ΄ λ˜μ—ˆμ„ 객체가, ν΄λ‘œμ € νŒ¨ν„΄μ—μ„œλŠ” λ©”λͺ¨λ¦¬ 상에 남아 있게 λ©λ‹ˆλ‹€. μ™ΈλΆ€ ν•¨μˆ˜ μŠ€μ½”ν”„κ°€ λ‚΄λΆ€ν•¨μˆ˜μ— μ˜ν•΄ μ–Έμ œλ“ μ§€ 참쑰될 수 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€. λ”°λΌμ„œ ν΄λ‘œμ €λ₯Ό λ‚¨λ°œν•  경우 퍼포먼슀 μ €ν•˜κ°€ λ°œμƒν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.
μ •μ˜: ν•¨μˆ˜μ™€ ν•¨μˆ˜κ°€ μ„ μ–Έλœ μ–΄νœ˜μ  ν™˜κ²½(lexical environment)의 μ‘°ν•©
* νŠΉμ§•: λ‚΄λΆ€ ν•¨μˆ˜κ°€ μ™ΈλΆ€ ν•¨μˆ˜ μ•ˆμ— μ„ μ–Έλœ λ³€μˆ˜μ— μ ‘κ·Όν•  수 μžˆλ‹€. λ‚΄λΆ€ ν•¨μˆ˜λ₯Ό ν΄λ‘œμ € ν•¨μˆ˜λΌκ³  λΆ€λ₯΄κΈ°λ„ ν•œλ‹€.
* μ‘μš©: namespacing, privacy, function factory, partially applied functions, ...
*
β€’
이λ₯Ό ν™œμš©ν•˜μ—¬ κΈ°μ‘΄ ν•¨μˆ˜κ°€ μ—¬λŸ¬ 번 μ‹€ν–‰λ˜λ©΄ κ²°κ³Όκ°€ λ³€λ™λ˜λŠ” ν•¨μˆ˜λ₯Ό, ν•œ 번 λ¦¬ν„΄λœ κ°’λ§Œ λ¦¬ν„΄ν•˜κ²Œ ν•˜λŠ” ν•¨μˆ˜(_.once)와
* κΈ°μ‘΄ ν•¨μˆ˜κ°€ μ¦‰μ‹œ μ‹€ν–‰ 되던 ν•¨μˆ˜λ₯Ό, 일정 μ‹œκ°„ 이후에 μ‹€ν–‰λ˜κ²Œ ν•˜λŠ” ν•¨μˆ˜(_.delay)둜 λ§Œλ“€μ–΄λ΄…μ‹œλ‹€.
*
* μ΄λŠ” 일반적인 ν”„λ‘œκ·Έλž˜λ° λ””μžμΈ νŒ¨ν„΄ 쀑 λ°μ½”λ ˆμ΄ν„°(λ˜λŠ” wrapper) νŒ¨ν„΄κ³Ό μœ μ‚¬ν•©λ‹ˆλ‹€.
* λ°μ½”λ ˆμ΄ν„° νŒ¨ν„΄μ€ 객체λ₯Ό κΎΈλ―Έκ±°λ‚˜(decorate) κ°μ‹Έμ„œ(wrap) κΈ°μ‘΄ 객체에 κΈ°λŠ₯ λ˜λŠ” 행동을 μΆ”κ°€ν•©λ‹ˆλ‹€.
* μžμ„Έν•œ λ‚΄μš©μ€ μ•„λž˜ 링크λ₯Ό ν™•μΈν•˜μ‹œκΈ° λ°”λžλ‹ˆλ‹€. Advancedν•œ λ‚΄μš©μ΄λ―€λ‘œ μ§€κΈˆ λ‹Ήμž₯ 읽지 μ•ŠμœΌμ…”λ„ λ©λ‹ˆλ‹€.
* 이둠: https://refactoring.guru/design-patterns/decorator
* κ΅¬ν˜„: https://www.dofactory.com/javascript/design-patterns/decorator