What is Closure?

closurejavascript

2018-04-28


개인적인 곡뢀 λ…ΈνŠΈλ‘œ 였λ₯˜κ°€ μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.

1. ν΄λ‘œμ €(Closure)λž€?

private ν•¨μˆ˜μ˜ λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•˜λŠ” 것, λ˜λŠ” 싀행이 λλ‚œ λΆ€λͺ¨ ν•¨μˆ˜ μŠ€μ½”ν”„μ˜ λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•˜λŠ” ν•¨μˆ˜λ₯Ό μ˜λ―Έν•œλ‹€.

// without closure
function Person(name) {
  var _name = name  // _name은 μˆ¨κ²¨μ§„ λ³€μˆ˜λΌλŠ” 것을 κ°•μ‘°ν•˜κΈ° μœ„ν•΄ μ‚¬μš©
}

var person = new Person('Jane')
console.log(person.name) // undefined

πŸ‘‰ Person ν•¨μˆ˜κ°€ μ‹€ν–‰λœ ν›„μ—λŠ” λ‹Ήμ—°νžˆ λ‚΄λΆ€ λ³€μˆ˜ name에 접근이 λΆˆκ°€λŠ₯ν•˜λ‹€. ν•˜μ§€λ§Œ ν΄λ‘œμ €λ₯Ό μ‚¬μš©ν•΄ λ‚΄λΆ€ λ³€μˆ˜μ— μ ‘κ·Όν•˜λŠ” ν•¨μˆ˜λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

// with closure
function Person(name) {
  var _name = name
  
  this.getName = function() {
    return _name  // μˆ¨κ²¨μ§„ λ³€μˆ˜ _name에 μ ‘κ·Όν•œλ‹€.
  }
}

var person = new Person('Jane')
console.log(person.getName()) // Jane

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

ν΄λ‘œμ €λ₯Ό μ‚¬μš©ν•˜λ©΄ λ‚΄λΆ€ λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•˜λŠ” ν•¨μˆ˜λ₯Ό λ¦¬ν„΄ν•΄μ„œ λ‚΄λΆ€ λ³€μˆ˜λ₯Ό 계속 κ°„μ§ν•˜λ„λ‘ λ§Œλ“€μˆ˜λ„ μžˆλ‹€.(좜처: μΈμ‚¬μ΄λ“œ μžλ°”μŠ€ν¬λ¦½νŠΈ(2016))

function parent() {
  const a = 100
  const child = function() {
    console.log(a)  // parent()의 λ‚΄λΆ€ λ³€μˆ˜ aλ₯Ό μ°Έμ‘°ν•œλ‹€.
  }
  return child   // parent() ν•¨μˆ˜λŠ” λ‚΄λΆ€ ν•¨μˆ˜ child()λ₯Ό λ¦¬ν„΄ν•œλ‹€.
}

const inner = parent()  // inner() ν•¨μˆ˜λŠ” λ¦¬ν„΄λœ child() ν•¨μˆ˜ 
inner() // 100
  1. parent() ν•¨μˆ˜μ˜ 싀행은 λλ‚¬μ§€λ§Œ λ‚΄λΆ€ λ³€μˆ˜ aλŠ” 가비지 μ»¬λ ‰νŒ…μ΄ λ˜μ§€ μ•ŠλŠ”λ‹€.
  2. inner() ν•¨μˆ˜λŠ” parent() ν•¨μˆ˜μ˜ 리턴값인 child()λ₯Ό ν• λ‹Ή λ°›μ•˜κ³ , κ·Έ child() ν•¨μˆ˜λŠ” λ³€μˆ˜ aλ₯Ό μ°Έμ‘°ν•˜κ³  있기 λ•Œλ¬Έμ— 100을 좜λ ₯ν•˜κ²Œ λœλ‹€.

πŸ‘‰ 가비지 μ»¬λ ‰μ…˜(garbage collection): λ©”λͺ¨λ¦¬ 관리 기법 μ€‘μ˜ ν•˜λ‚˜λ‘œ, ν”„λ‘œκ·Έλž¨μ΄ λ™μ μœΌλ‘œ ν• λ‹Ήν–ˆλ˜ λ©”λͺ¨λ¦¬ μ˜μ—­ μ€‘μ—μ„œ ν•„μš”μ—†κ²Œ 된 μ˜μ—­μ„ ν•΄μ œν•˜λŠ” κΈ°λŠ₯이닀.

const a = function() {
  const counter = 0
  return function() {
    counter += 1
    return counter
  }
}

const b = a()
b() // function() { counter += 1; return counter }
// 이 counterλŠ” μ–΄λ””μ„œ 왔지? μ—¬μ „νžˆ μ ‘κ·Ό κ°€λŠ₯ν•˜μ§€λ§Œ counter λ³€μˆ˜λŠ” λ”λŸ½ν˜€μ§€μ§€ μ•ŠλŠ”λ‹€.
  • μŠ€μ½”ν”„ - ν•¨μˆ˜λ‚˜ {} λ°–μ—μ„œ μ •μ˜λ˜λŠ” λ³€μˆ˜λŠ” λͺ¨λ‘ global variable 이닀.

bλŠ” a λ‚΄λΆ€μ—μ„œ λ¦¬ν„΄λ˜λŠ” ν•¨μˆ˜κ°€ λœλ‹€. counter = 0; function() { counter += 1; return counter}와 incrementing ν•˜λŠ” κΈ°λŠ₯은 κ°™μ§€λ§Œ μ™ΈλΆ€μ—μ„œ counter에 접근이 λΆˆκ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ— μ „μ—­ λ³€μˆ˜λ₯Ό λ”λŸ½νžˆμ§€ μ•Šμ„ 수 μžˆλ‹€λŠ” 차이가 μžˆλ‹€. λ³€μˆ˜ 뿐만 μ•„λ‹ˆλΌ ν•¨μˆ˜, 객체도 μ΄λŸ°μ‹μœΌλ‘œ 숨길 수 μžˆλ‹€. μ΄λŸ°μ‹μœΌλ‘œ private λ³€μˆ˜λ„ κ΅¬ν˜„ κ°€λŠ₯.


3. μ–Έμ œ μ‚¬μš©ν• κΉŒ? (feat. event listener)

ν΄λ‘œμ €λŠ” 이벀트 λ¦¬μŠ€λ„ˆμ˜ μ½œλ°±μ— 인자λ₯Ό 같이 λ„˜κ²¨μ€„ λ•Œ μ‚¬μš©ν•  수 μžˆλ‹€.

// anchor νƒœκ·Έλ₯Ό 클릭할 λ•Œ, λ¦¬ν”„λ ˆμ‹œλ₯Ό ν•˜μ§€ μ•Šκ³  각 anchor의 indexλ₯Ό λ„μš°λŠ” μ˜ˆμ‹œ

function registerHandlers() {
  const anchors = document.querySelectorAll('a')
  Array.from(anchors, (a, index) => {
    a.addEventListener('click', (event) => alertIndex(event, index))
  })
}

function alertIndex(event, index) {
  event.preventDefault()
  return alert(index)
} 

registerHandlers()