본문으둜 κ±΄λ„ˆλ›°κΈ°

🌈 Chapter 5: ν΄λ‘œμ €

πŸ“š ν΄λ‘œμ €μ˜ 의미 및 원리 이해​

  • ν΄λ‘œμ €(Closure)λŠ” μ—¬λŸ¬ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄μ—μ„œ λ“±μž₯ν•˜λŠ” 보편적인 νŠΉμ„±μ΄λ‹€.
  • ν΄λ‘œμ €λ₯Ό ν•œ λ¬Έμž₯으둜 μš”μ•½
    • μžμ‹ μ„ λ‚΄ν¬ν•˜λŠ” ν•¨μˆ˜μ˜ μ»¨ν…μŠ€νŠΈμ— μ ‘κ·Όν•  수 μžˆλŠ” ν•¨μˆ˜ (μžλ°”μŠ€ν¬λ¦½νŠΈ 핡심 κ°€μ΄λ“œ)
    • ν•¨μˆ˜κ°€ νŠΉμ • μŠ€μ½”ν”„μ— μ ‘κ·Όν•  수 μžˆλ„λ‘ μ˜λ„μ μœΌλ‘œ κ·Έ μŠ€μ½”ν”„μ—μ„œ μ •μ˜ν•˜λŠ” 것 (λŸ¬λ‹ μžλ°”μŠ€ν¬λ¦½νŠΈ)
    • ν•¨μˆ˜λ₯Ό μ„ μ–Έν•  λ•Œ λ§Œλ“€μ–΄μ§€λŠ” μœ νš¨λ²”μœ„κ°€ 사라진 후에도 ν˜ΈμΆœν•  수 μžˆλŠ” ν•¨μˆ˜ (μžλ°”μŠ€ν¬λ¦½νŠΈ λ‹Œμž λΉ„κΈ‰)
    • 이미 생λͺ… 주기상 λλ‚œ μ™ΈλΆ€ ν•¨μˆ˜μ˜ λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•˜λŠ” ν•¨μˆ˜ (μΈμ‚¬μ΄λ“œ μžλ°”μŠ€ν¬λ¦½νŠΈ)
    • μžμœ λ³€μˆ˜κ°€ μžˆλŠ” ν•¨μˆ˜μ™€ μžμœ λ³€μˆ˜λ₯Ό μ•Œ 수 μžˆλŠ” ν™˜κ²½μ˜ κ²°ν•© (Head First Javascript Programming)
    • 둜컬 λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•˜κ³  μžˆλŠ” ν•¨μˆ˜ λ‚΄μ˜ ν•¨μˆ˜ (μžλ°”μŠ€ν¬λ¦½νŠΈ λ§ˆμŠ€ν„°λΆ)
    • μžμ‹ μ΄ 생성될 λ•Œμ˜ μŠ€μ½”ν”„μ—μ„œ μ•Œ 수 μžˆμ—ˆλ˜ λ³€μˆ˜λ“€ 쀑 μ–Έμ  κ°€ μžμ‹ μ΄ 싀행될 λ•Œ μ‚¬μš©ν•  λ³€μˆ˜λ“€λ§Œμ„ κΈ°μ–΅ν•˜λ©° μœ μ§€μ‹œν‚€λŠ” ν•¨μˆ˜ (ν•¨μˆ˜ν˜• μžλ°”μŠ€ν¬λ¦½νŠΈ ν”„λ‘œκ·Έλž˜λ°)
    • ν΄λ‘œμ €λŠ” ν•¨μˆ˜μ™€ κ·Έ ν•¨μˆ˜κ°€ 선언될 λ‹Ήμ‹œμ˜ lexical environment(λ ‰μ‹œμ»¬ ν™˜κ²½)의 μƒν˜Έκ΄€κ³„μ— λ”°λ₯Έ ν˜„μƒ (MDN)
  • μ–΄λ–€ μ»¨ν…μŠ€νŠΈ Aμ—μ„œ μ„ μ–Έν•œ λ‚΄λΆ€ν•¨μˆ˜ B의 μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ ν™œμ„±ν™”λœ μ‹œμ μ—λŠ” B의 outerEnvironmentReferenceκ°€ μ°Έμ‘°ν•˜λŠ” λŒ€μƒμΈ A의 LexicalEnvironment에도 접근이 κ°€λŠ₯ν•˜λ‹€. Aμ—μ„œλŠ” Bμ—μ„œ μ„ μ–Έν•œ λ³€μˆ˜μ— μ ‘κ·Όν•  수 μ—†μ§€λ§Œ Bμ—μ„œλŠ” Aμ—μ„œ μ„ μ–Έν•œ λ³€μˆ˜μ— 접근이 κ°€λŠ₯ν•˜λ‹€.
  • λ‚΄λΆ€ν•¨μˆ˜μ—μ„œ μ™ΈλΆ€ λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•˜μ§€ μ•ŠλŠ” κ²½μš°λŠ” ν•΄λ‹Ήν•˜μ§€ μ•ŠλŠ”λ‹€. 즉, 선언될 λ‹Ήμ‹œμ˜ LexicalEnvironmentμ™€μ˜ μƒν˜Έκ΄€κ³„μ΄λ‹€.
var outer = function() {
var a = 1;

var inner = function() {
console.log(++a); // 2
};

inner();
};

outer();
  • μœ„ μ˜ˆμ—μ„œ inner ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œλŠ” aλ₯Ό μ„ μ–Έν•˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— environmentRecordμ—μ„œ 값을 찾지 λͺ»ν•˜λ―€λ‘œ outerEnvironmentReference에 μ§€μ •λœ μƒμœ„ μ»¨ν…μŠ€νŠΈμΈ LexicalEnvironment에 μ ‘κ·Όν•΄μ„œ λ‹€μ‹œ aλ₯Ό μ°ΎλŠ”λ‹€.
  • outer ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ’…λ£Œλ˜λ©΄ LexicalEnvironment에 μ§€μ •λœ μ‹λ³„μžλ“€(a, inner)에 λŒ€ν•œ μ°Έμ‘°λ₯Ό μ§€μš΄λ‹€. 그러면 각 μ£Όμ†Œμ— μ €μž₯돼 있던 값듀은 μžμ‹ μ„ μ°Έμ‘°ν•˜λŠ” λ³€μˆ˜κ°€ ν•˜λ‚˜λ„ μ—†κ²Œ λ˜λ―€λ‘œ 가비지 μ»¬λ ‰ν„°μ˜ μˆ˜μ§‘ λŒ€μƒμ΄ 될 것이닀.
var outer = function() {
var a = 1;

var inner = function() {
return ++a;
};

return inner();
};

var outer2 = outer();
console.log(outer2); // 2
  • μœ„ μ˜ˆμ œμ—μ„œλŠ” inner ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•œ κ²°κ³Όλ₯Ό λ¦¬ν„΄ν•˜κ³  μžˆμœΌλ―€λ‘œ 결과적으둜 outer ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ’…λ£Œλœ μ‹œμ μ—λŠ” a λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•˜λŠ” λŒ€μƒμ΄ 없어진닀.
  • μœ„ 두 μ˜ˆμ œμ—μ„œ outer ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ’…λ£Œλ˜κΈ° 이전에 inner ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ’…λ£ŒλΌ 있으며, 이후 λ³„λ„μ˜ inner ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  수 μ—†λ‹€λŠ” 곡톡점이 μžˆλ‹€.
  • κ·Έλ ‡λ‹€λ©΄ outer의 μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ’…λ£Œλœ 후에도 inner ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  수 있게 λ§Œλ“€λ©΄ μ–΄λ–¨κΉŒ?
var outer = function() {
var a = 1;

var inner = function() {
return ++a;
};

return inner;
};

var outer2 = outer();
console.log(outer2()); // 2
console.log(outer2()); // 3
  • μœ„ μ˜ˆμ œμ—μ„œ inner ν•¨μˆ˜ 자체λ₯Ό λ°˜ν™˜ν–ˆλ‹€. 그러면 outer ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ’…λ£Œλ  λ•Œ outer2 λ³€μˆ˜λŠ” outer의 μ‹€ν–‰ 결과인 inner ν•¨μˆ˜λ₯Ό μ°Έμ‘°ν•˜κ²Œ 될 것이닀.
  • inner ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈμ˜ environmentRecordμ—λŠ” μˆ˜μ§‘ν•  정보가 μ—†λ‹€. outerEnvironmentReferenceμ—λŠ” inner ν•¨μˆ˜κ°€ μ„ μ–Έλœ μœ„μΉ˜μ˜ LexicalEnvironmentκ°€ μ°Έμ‘°λ³΅μ‚¬λœλ‹€.
  • inner ν•¨μˆ˜λŠ” outer ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ μ„ μ–ΈλμœΌλ―€λ‘œ, outer ν•¨μˆ˜μ˜ LexicalEnvironmentκ°€ λ‹΄κΈΈ 것이닀.
  • 이제 μŠ€μ½”ν”„ 체이닝에 따라 outerμ—μ„œ μ„ μ–Έν•œ λ³€μˆ˜ a에 μ ‘κ·Όν•΄μ„œ 1만큼 μ¦κ°€μ‹œν‚¨ ν›„ κ·Έ 값인 2λ₯Ό λ°˜ν™˜ν•˜κ³ , inner ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ’…λ£Œλœλ‹€.
  • 그런데 inner ν•¨μˆ˜μ˜ μ‹€ν–‰ μ‹œμ μ—λŠ” outer ν•¨μˆ˜λŠ” 이미 싀행이 μ’…λ£Œλœ μƒνƒœμΈλ° outer ν•¨μˆ˜μ˜ LexicalEnvironment에 μ–΄λ–»κ²Œ μ ‘κ·Όν•˜λŠ” κ²ƒμΌκΉŒ?
  • μ΄λŠ” 가비지 μ»¬λ ‰ν„°μ˜ λ™μž‘ 방식 λ•Œλ¬ΈμΈλ° 가비지 μ»¬λ ‰ν„°λŠ” μ–΄λ–€ 값을 μ°Έμ‘°ν•˜λŠ” λ³€μˆ˜κ°€ ν•˜λ‚˜λΌλ„ μžˆλ‹€λ©΄ κ·Έ 값은 μˆ˜μ§‘ λŒ€μƒμ— ν¬ν•¨μ‹œν‚€μ§€ μ•ŠλŠ”λ‹€.
  • outer ν•¨μˆ˜λŠ” μ‹€ν–‰ μ’…λ£Œ μ‹œμ μ— inner ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•œλ‹€. μ™ΈλΆ€ν•¨μˆ˜μΈ outer의 싀행이 μ’…λ£Œλ˜λ”λΌλ„ λ‚΄λΆ€ ν•¨μˆ˜μΈ inner ν•¨μˆ˜λŠ” μ–Έμ  κ°€ outer2λ₯Ό μ‹€ν–‰ν•¨μœΌλ‘œμ¨ 호좜될 κ°€λŠ₯성이 μ—΄λ¦° 것이닀. λ•Œλ¬Έμ— 가비지 μ»¬λ ‰ν„°μ˜ μˆ˜μ§‘ λŒ€μƒμ—μ„œ μ œμ™Έκ°€ λ˜λŠ” 것이닀.
  • 이처럼 ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ’…λ£Œλœ 후에도 LexicalEnvironmentκ°€ 가비지 μ»¬λ ‰ν„°μ˜ μˆ˜μ§‘ λŒ€μƒμ—μ„œ μ œμ™Έλ˜λŠ” κ²½μš°λŠ” λ§ˆμ§€λ§‰ 예제처럼 μ§€μ—­λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•˜λŠ” λ‚΄λΆ€ν•¨μˆ˜κ°€ μ™ΈλΆ€λ‘œ μ „λ‹¬λœ κ²½μš°κ°€ μœ μΌν•˜λ‹€.

ν΄λ‘œμ €λ₯Ό λ‹€μ‹œ μ •μ˜ν•΄λ³΄λ©΄ ν΄λ‘œμ €λž€ μ–΄λ–€ ν•¨μˆ˜ Aμ—μ„œ μ„ μ–Έν•œ λ³€μˆ˜ aλ₯Ό μ°Έμ‘°ν•˜λŠ” λ‚΄λΆ€ν•¨μˆ˜ Bλ₯Ό μ™ΈλΆ€λ‘œ 전달할 경우 A의 μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ’…λ£Œλœ 이후에도 λ³€μˆ˜ aκ°€ 사라지지 μ•ŠλŠ” ν˜„μƒμ΄λ‹€.

  • ν•œκ°€μ§€ μ£Όμ˜ν•  점은 μ™ΈλΆ€λ‘œ 전달이 곧 returnλ§Œμ„ μ˜λ―Έν•˜λŠ” 것은 μ•„λ‹ˆλ‹€. μ•„λž˜ μ½”λ“œλŠ” return없이도 ν΄λ‘œμ €κ°€ λ°œμƒν•˜λŠ” 상황이닀.
// setInterval/setTimeout
(function () {
var a = 0;
var intervalId = null;
var inner = function () {
if(++a >= 10) {
clearInterval(intervalId);
}

console.log(a);
};

intervalId = setInterval(inner, 1000);
})();

// eventListener
(function () {
var count = 0;
var button = document.createElement('button');

button.innerText = 'click';
button.addEventListener('click', function () {
console.log(++count, 'times clicked');
});

document.body.appendChild(button);
})();
  • μœ„ 두 상황 λͺ¨λ‘ μ§€μ—­λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•˜λŠ” λ‚΄λΆ€ν•¨μˆ˜λ₯Ό 외뢀에 μ „λ‹¬ν–ˆκΈ° λ•Œλ¬Έμ— ν΄λ‘œμ €μ΄λ‹€.

πŸ“š ν΄λ‘œμ €μ™€ λ©”λͺ¨λ¦¬ 관리​

  • ν΄λ‘œμ €λŠ” μ–΄λ–€ ν•„μš”μ— μ˜ν•΄ μ˜λ„μ μœΌλ‘œ ν•¨μˆ˜μ˜ μ§€μ—­λ³€μˆ˜λ₯Ό λ©”λͺ¨λ¦¬λ₯Ό μ†Œλͺ¨ν•˜λ„둝 ν•¨μœΌλ‘œμ¨ λ°œμƒν•œλ‹€. κ·Έλ ‡λ‹€λ©΄ κ·Έ ν•„μš”μ„±μ΄ 사라진 μ‹œμ μ—λŠ” λ”λŠ” λ©”λͺ¨λ¦¬λ₯Ό μ†Œλͺ¨ν•˜μ§€ μ•Šκ²Œ ν•΄μ£Όλ©΄ λœλ‹€.
// return 에 μ˜ν•œ ν΄λ‘œμ €μ˜ λ©”λͺ¨λ¦¬ ν•΄μ œ
var outer = (function () {
var a = 1;

var inner = function () {
return ++a;
};

return inner;
})();

console.log(outer());
console.log(outer());

outer = null; // outer μ‹λ³„μžμ˜ inner ν•¨μˆ˜ μ°Έμ‘°λ₯Ό 끊음

console.log(outer()); // TypeError: outer is not a function
  • setInterval에 μ˜ν•œ ν΄λ‘œμ € λ©”λͺ¨λ¦¬ ν•΄μ œ
(function () {
var a = 0;
var intervalId = null;
var inner = function () {
if(++a >= 10) {
clearInterval(intervalId);
inner = null; // inner μ‹λ³„μžμ˜ ν•¨μˆ˜ μ°Έμ‘°λ₯Ό 끊음
}

console.log(a);
};

intervalId = setInterval(inner, 1000);
})();
  • eventListener에 μ˜ν•œ ν΄λ‘œμ € λ©”λͺ¨λ¦¬ ν•΄μ œ
(function () {
var count = 0;
var button = document.createElement('button');
button.innerText = 'click';

var clickHandler = function () {
console.log(++count, 'times clicked');
if(count >= 10) {
button.removeEventListener('click', clickHandler);
clickHandler = null; // clickHandler μ‹λ³„μžμ˜ ν•¨μˆ˜ μ°Έμ‘°λ₯Ό 끊음
}
};

button.addEventListener('click', clickHandler);
document.body.appendChild(button);
})();

πŸ“š ν΄λ‘œμ € ν™œμš© 사둀​

🎈 콜백 ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ μ™ΈλΆ€ 데이터λ₯Ό μ‚¬μš©ν•˜κ³ μž ν•  λ•Œβ€‹

var fruits = ['apple', 'banana', 'peach'];
var ul = document.createElement('ul');

fruits.forEach(function (fruit) { // A
var li = document.createElement('li');
li.innerText = fruit;
li.addEventListener('click', function () { // B
alert('your choice is ' + fruit);
});

ul.appendChild(li);
});

document.body.appendChild(ul);
  • μœ„ μ˜ˆμ œμ—μ„œ A 콜백 ν•¨μˆ˜λŠ” κ·Έ λ‚΄λΆ€μ—μ„œ μ™ΈλΆ€ λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³  μžˆμœΌλ―€λ‘œ ν΄λ‘œμ €κ°€ μ—†μ§€λ§Œ, addEventListener에 λ„˜κ²¨μ€€ B 콜백 ν•¨μˆ˜μ—λŠ” fruitμ΄λΌλŠ” μ™ΈλΆ€ λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•˜κ³  μžˆμœΌλ―€λ‘œ ν΄λ‘œμ €κ°€ μžˆλ‹€.
  • AλŠ” fruits의 개수만큼 μ‹€ν–‰λ˜λ©°, κ·Έλ•Œλ§ˆλ‹€ μƒˆλ‘œμš΄ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ ν™œμ„±λ  것이닀. A의 μ‹€ν–‰ μ’…λ£Œ 여뢀와 λ¬΄κ΄€ν•˜κ²Œ 클릭 μ΄λ²€νŠΈμ— μ˜ν•΄ 각 μ»¨ν…μŠ€νŠΈμ˜ Bκ°€ 싀행될 λ•ŒλŠ” B의 outerEnvironmentReferenceκ°€ A의 LexicalEnvironmentλ₯Ό μ°Έμ‘°ν•˜κ²Œ 될 것이닀. λ”°λΌμ„œ μ΅œμ†Œν•œ B ν•¨μˆ˜κ°€ μ°Έμ‘°ν•  μ˜ˆμ •μΈ λ³€μˆ˜ fruit에 λŒ€ν•΄μ„œλŠ” Aκ°€ μ’…λ£Œλœ 후에도 GC λŒ€μƒμ—μ„œ μ œμ™Έλ˜μ–΄ 계속 μ°Έμ‘°κ°€ κ°€λŠ₯ν•˜λ‹€.
  • 이제 λ°˜λ³΅μ„ 쀄이기 μœ„ν•΄ Bλ₯Ό μ™ΈλΆ€λ‘œ 뢄리해본닀. 즉 fruitλ₯Ό 인자둜 λ°›μ•„ 좜λ ₯ν•˜λŠ” ν˜•νƒœλ‘œ..
var fruits = ['apple', 'banana', 'peach'];
var ul = document.createElement('ul');

var alertFruit = function (fruit) {
alert('your choice is ' + fruit);
}
fruits.forEach(function (fruit) { // A
var li = document.createElement('li');
li.innerText = fruit;
// 첫 번째 μΈμžμ— 이벀트 객체λ₯Ό μ£Όμž…ν•˜κΈ° λ•Œλ¬Έμ— bind λ©”μ„œλ“œλ₯Ό ν• μš©
li.addEventListener('click', alertFruit.bind(null, fruit));

ul.appendChild(li);
});

document.body.appendChild(ul);
  • λ‹€λ§Œ μ΄λ ‡κ²Œ ν•˜λ©΄ 이벀트 객체가 인자둜 λ„˜μ–΄μ˜€λŠ” μˆœμ„œκ°€ λ°”λ€ŒλŠ” 점 및 ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œμ˜ thisκ°€ μ›λž˜μ˜ 그것과 λ‹¬λΌμ§€λŠ” 점을 κ°μ•ˆν•΄μ•Ό ν•œλ‹€. κ·Έλ ‡κΈ° λ•Œλ¬Έμ— μ—¬κΈ°μ„œ κ³ μ°¨ν•¨μˆ˜λ₯Ό ν™œμš©ν•œλ‹€.
var fruits = ['apple', 'banana', 'peach'];
var ul = document.createElement('ul');

var alertFruitBuilder = function (fruit) {
return function () {
alert('your choice is ' + fruit);
}
}
fruits.forEach(function (fruit) { // A
var li = document.createElement('li');
li.innerText = fruit;
// 첫 번째 μΈμžμ— 이벀트 객체λ₯Ό μ£Όμž…ν•˜κΈ° λ•Œλ¬Έμ— bind λ©”μ„œλ“œλ₯Ό ν• μš©
li.addEventListener('click', alertFruitBuilder(fruit));

ul.appendChild(li);
});

document.body.appendChild(ul);
  • alertFruitBuilder ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•˜λ©΄μ„œ fruit 값을 인자둜 μ „λ‹¬ν–ˆκ³  이 ν•¨μˆ˜μ˜ μ‹€ν–‰ κ²°κ³Όκ°€ λ‹€μ‹œ ν•¨μˆ˜κ°€ 되며, μ΄λ ‡κ²Œ λ°˜ν™˜λœ ν•¨μˆ˜λ₯Ό λ¦¬μŠ€λ„ˆμ— 콜백 ν•¨μˆ˜λ‘œμ¨ 전달할 것이닀.
  • 이후 클릭 μ΄λ²€νŠΈκ°€ λ°œμƒν•˜λ©΄ 이 ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ—΄λ¦¬λ©΄μ„œ alertFruitBuilder의 인자둜 λ„˜μ–΄μ˜¨ fruitλ₯Ό outerEnvironmentReference에 μ˜ν•΄ μ°Έμ‘°ν•  수 μžˆλ‹€. 즉, alertFruitBuilder의 μ‹€ν–‰ 결과둜 λ°˜ν™˜λœ ν•¨μˆ˜μ—λŠ” ν΄λ‘œμ €κ°€ μ‘΄μž¬ν•œλ‹€.

🎈 μ ‘κ·Ό κΆŒν•œ μ œμ–΄(정보 은닉)​

  • ν΄λ‘œμ €λ₯Ό μ΄μš©ν•˜λ©΄ ν•¨μˆ˜ μ°¨μ›μ—μ„œ publicν•œ κ°’κ³Ό privateν•œ 값을 κ΅¬λΆ„ν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€.
var outer = function () {
var a = 1;

var inner = function () {
return ++a;
};

return inner;
};

var outer2 = outer();
console.log(outer2()); // 2
console.log(outer2()); // 3

return {
get move() {

},
run: function() {

}
}
  • outer ν•¨μˆ˜λ₯Ό μ’…λ£Œν•  λ•Œ inner ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•¨μœΌλ‘œμ¨ outer ν•¨μˆ˜μ˜ μ§€μ—­λ³€μˆ˜μΈ a의 값을 μ™ΈλΆ€μ—μ„œλ„ 읽을 수 있게 λ˜μ—ˆλ‹€. 이처럼 ν΄λ‘œμ €λ₯Ό ν™œμš©ν•˜λ©΄ μ™ΈλΆ€ μŠ€μ½”ν”„μ—μ„œ ν•¨μˆ˜ λ‚΄λΆ€μ˜ λ³€μˆ˜λ“€ 쀑 μ„ νƒμ μœΌλ‘œ 일뢀 λ³€μˆ˜μ— λŒ€ν•œ μ ‘κ·Ό κΆŒν•œμ„ λΆ€μ—¬ν•  수 μžˆλ‹€. return을 ν™œμš©ν•΄μ„œ κ°€λŠ₯ν•˜λ‹€.
  • outer ν•¨μˆ˜λŠ” μ™ΈλΆ€(μ „μ—­ μŠ€μ½”ν”„)λ‘œλΆ€ν„° μ² μ €ν•˜κ²Œ 격리된 λ‹«νžŒ 곡간이닀. μ™ΈλΆ€μ—μ„œλŠ” μ™ΈλΆ€ 곡간에 λ…ΈμΆœλΌ μžˆλŠ” outer λΌλŠ” λ³€μˆ˜λ₯Ό 톡해 outer ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•  μˆ˜λŠ” μžˆμ§€λ§Œ, outer ν•¨μˆ˜ λ‚΄λΆ€μ—λŠ” μ–΄λ– ν•œ κ°œμž…λ„ ν•  수 μ—†λ‹€. μ™ΈλΆ€μ—μ„œλŠ” 였직 outer ν•¨μˆ˜κ°€ returnν•œ μ •λ³΄μ—λ§Œ μ ‘κ·Όν•  수 μžˆλ‹€. return 값이 외뢀에 μ œκ³΅λ˜λŠ” μœ μΌν•œ μˆ˜λ‹¨μ΄λ‹€.
  • κ·Έλ ‡κΈ° λ•Œλ¬Έμ— 외뢀에 μ œκ³΅ν•˜κ³ μž ν•˜λŠ” 정보듀을 λͺ¨μ•„μ„œ returnν•˜κ³ , λ‚΄λΆ€μ—μ„œλ§Œ μ‚¬μš©ν•  정보듀은 returnν•˜μ§€ μ•ŠλŠ” κ²ƒμœΌλ‘œ μ ‘κ·Ό κΆŒν•œ μ œμ–΄κ°€ κ°€λŠ₯ν•œ 것이닀.

🎈 λΆ€λΆ„ 적용 ν•¨μˆ˜β€‹

  • λΆ€λΆ„ 적용 ν•¨μˆ˜λž€ n 개의 인자λ₯Ό λ°›λŠ” ν•¨μˆ˜μ— 미리 m개의 인자만 λ„˜κ²¨ κΈ°μ–΅μ‹œμΌ°λ‹€κ°€, λ‚˜μ€‘μ— (n - m)개의 인자λ₯Ό λ„˜κΈ°λ©΄ λΉ„λ‘œμ†Œ μ›λž˜ ν•¨μˆ˜μ˜ μ‹€ν–‰ κ²°κ³Όλ₯Ό 얻을 수 μžˆκ² λ” ν•˜λŠ” ν•¨μˆ˜μ΄λ‹€.
var partial = function () {
var originalPartialArgs = arguments;
var func = originalPartialArgs[0];

if (typeof func !== 'function') {
throw new Error('첫 번째 μΈμžκ°€ ν•¨μˆ˜κ°€ μ•„λ‹™λ‹ˆλ‹€.');
}

return function () {
var partialArgs = Array.prototype.slice.call(originalPartialArgs, 1);
var restArgs = Array.prototype.slice.call(arguments);
return func.apply(this, partialArgs.concat(restArgs));
};
};

var add = function () {
var result = 0;
for (var i = 0; i < arguments.length; i++) {
result += arguments[i];
}
return result;
};

var addPartial = partial(add, 1, 2, 3, 4, 5);
console.log(addPartial(6, 7, 8, 9, 10)); // 55

var dog = {
name: '강아지',
greet: partial(function(prefix, suffix) {
return prefix + this.name + suffix;
}, 'μ™ˆμ™ˆ, ');
};

dog.greet('μž…λ‹ˆλ‹€!'); // μ™ˆμ™ˆ, κ°•μ•„μ§€μž…λ‹ˆλ‹€!
  • λ‹€μŒ μ˜ˆμ œλŠ” λ””λ°”μš΄μŠ€(debounce)에 λŒ€ν•œ μ˜ˆμ œμ΄λ‹€. λ””λ°”μš΄μŠ€λŠ” 짧은 μ‹œκ°„ λ™μ•ˆ λ™μΌν•œ μ΄λ²€νŠΈκ°€ 많이 λ°œμƒν•  경우 이λ₯Ό μ „λΆ€ μ²˜λ¦¬ν•˜μ§€ μ•Šκ³  처음 λ˜λŠ” λ§ˆμ§€λ§‰μ— λ°œμƒν•œ μ΄λ²€νŠΈμ— λŒ€ν•΄ ν•œ 번만 μ²˜λ¦¬ν•˜λŠ” κ²ƒμœΌλ‘œ, ν”„λŸ°νŠΈμ—”λ“œ μ„±λŠ₯ μ΅œμ ν™”μ— 큰 도움을 μ£ΌλŠ” κΈ°λŠ₯ 쀑 ν•˜λ‚˜λ‹€. (scroll, wheel, mousemove. resizeλ“± 적용)
var debounce = function (eventName, func, wait) {
var timeoutId = null;

return function (event) {
var self = this;

console.log(eventName, 'event λ°œμƒ');

clearTimeout(timeoutId);
timeoutId = setTimeout(func.bind(self, event), wait);
};
};

var moveHandler = function (e) {
console.log('move event 처리');
};

var wheelHandler = function (e) {
console.log('wheel event 처리');
};

document.body.addEventListener('mousemove', debounce('move', moveHandler, 500));
document.body.addEventListener('mousewheel', debounce('wheel', wheelHandler, 700));
  • 졜초 eventκ°€ λ°œμƒν•˜λ©΄ timeout의 λŒ€κΈ°μ—΄μ— wait μ‹œκ°„ λ’€ funcλ₯Ό μ‹€ν–‰ν•œλ‹€. 그런데 wait μ‹œκ°„μ΄ κ²½κ³Όν•˜κΈ° 이전에 λ‹€μ‹œ λ™μΌν•œ eventκ°€ λ°œμƒν•˜λ©΄ clearTimeout으둜 무쑰건 λŒ€κΈ°νλ₯Ό μ΄ˆκΈ°ν™”ν•˜κ²Œ ν•œλ‹€. λ‹€μ‹œ μƒˆλ‘œμš΄ λŒ€κΈ°μ—΄μ„ λ“±λ‘ν•œλ‹€.

🎈 컀링 ν•¨μˆ˜β€‹

  • 컀링 ν•¨μˆ˜λž€ μ—¬λŸ¬ 개의 인자λ₯Ό λ°›λŠ” ν•¨μˆ˜λ₯Ό ν•˜λ‚˜μ˜ 인자만 λ°›λŠ” ν•¨μˆ˜λ‘œ λ‚˜λˆ μ„œ 순차적으둜 호좜될 수 있게 체인 ν˜•νƒœλ‘œ κ΅¬μ„±ν•œ 것을 λ§ν•œλ‹€.
  • 컀링은 ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ 인자λ₯Ό μ „λ‹¬ν•˜λŠ” 것을 μ›μΉ™μœΌλ‘œ ν•˜κ³  쀑간 κ³Όμ •μƒμ˜ ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•œ κ²°κ³ΌλŠ” κ·Έλ‹€μŒ 인자λ₯Ό λ°›κΈ° μœ„ν•΄ λŒ€κΈ°λ§Œ ν•  뿐으둜, λ§ˆμ§€λ§‰ μΈμžκ°€ μ „λ‹¬λ˜κΈ° μ „κΉŒμ§€λŠ” 원본 ν•¨μˆ˜κ°€ μ‹€ν–‰λ˜μ§€ μ•ŠλŠ”λ‹€.
var curry3 = function (func) {
return function (a) {
return function (b) {
return func(a, b);
};
};
};

var getMaxWith10 = curry3(Math.max)(10);
console.log(getMaxWith10(8)); // 10
console.log(getMaxWith10(25)); // 25

var getMinWith10 = curry3(Math.min)(10);
console.log(getMinWith10(8)); // 8
console.log(getMinWith10(25)); // 10
  • 각 λ‹¨κ³„μ—μ„œ 받은 μΈμžλ“€μ€ λͺ¨λ‘ λ§ˆμ§€λ§‰ λ‹¨κ³„μ—μ„œ μ°Έμ‘°ν•  κ²ƒμ΄λ―€λ‘œ GCλ˜μ§€ μ•Šκ³  λ©”λͺ¨λ¦¬μ— 차곑차곑 μŒ“μ˜€λ‹€κ°€, λ§ˆμ§€λ§‰ 호좜둜 μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ’…λ£Œλœ 후에야 λΉ„λ‘œμ†Œ ν•œκΊΌλ²ˆμ— GC의 수거 λŒ€μƒμ΄ λœλ‹€.
  • 즉, λ‹Ήμž₯ ν•„μš”ν•œ μ •λ³΄λ§Œ λ°›μ•„μ„œ μ „λ‹¬ν•˜κ³  또 ν•„μš”ν•œ 정보가 λ“€μ–΄μ˜€λ©΄ μ „λ‹¬ν•˜λŠ” μ‹μœΌλ‘œ ν•˜λ©΄ κ²°κ΅­ λ§ˆμ§€λ§‰ μΈμžκ°€ λ„˜μ–΄κ°ˆ λ•ŒκΉŒμ§€ ν•¨μˆ˜ 싀행을 λ―Έλ£° 수 μžˆλ‹€. 이λ₯Ό ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž¨λ°μ—μ„œ 지연싀행이라고 ν•œλ‹€.