javascript closures by example - Lee-hyuna/33-js-concepts-kr GitHub Wiki
์์ ๋ก ์ดํด๋ณด๋ ์๋ฐ์คํฌ๋ฆฝํธ ํด๋ก์
์๋ฌธ: JavaScript closures by example
ํด๋ก์ ๋ฅผ ์ฌ์ฉํ๋ ๋ฒ์ ์๋ฉด ๋งค์ฐ ์ ์ฉํ๋ค. ๋ฌธ์ ๋ ๋ง์ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ๋ฐ์๊ฐ ํด๋ก์ ๋ฅผ ์ฌ์ฉํ๋ ๋ฒ์ ๋ชจ๋ฅธ๋ค๋ ๊ฒ์ด๋ค. ์ด ๊ฐ์ด๋๋ฅผ ์ฝ์ ํ ํด๋ก์ ๊ฐ ๋ฌด์์ด๊ณ ์ด๋ป๊ฒ ์๋ํ๋์ง, ์ธ์ ์ฌ์ฉํ๋ ์ง ์ ์ดํดํ๊ธธ ๋ฐ๋๋ค.
1. ํด๋ก์ ๋ ๋ฌด์์ธ๊ฐ?
MDN(Mozilla Developer Network)์ ๋์ ์๋ ํด๋ก์ ์ ์ ์๋ฅผ ์ธ์ฉํ์๋ฉด, "ํด๋ก์ ๋ ๋ ๋ฆฝ์ ์ธ ๋ณ์๋ฅผ ์ฐธ์กฐํ๋ ํจ์์ด๋ค. ๋ค์ ๋งํด ํด๋ก์ ์ ์ ์ ๋ ํจ์๋ ์์ฑ๋ ํ๊ฒฝ์ '๊ธฐ์ต'ํ๋ค." ์๋์ ์๋ฅผ ๋ณด์.
var outerFunc = function() {
var message = "Hello, World!";
var innerFunc = function() {
return message;
}
return innerFunc;
}
์๋ฐ์คํฌ๋ฆฝํธ๋ ๋ค๋ฅธ ์ธ์ด์ฒ๋ผ ๋ธ๋ก ๋ ๋ฒจ ๋ฒ์ ์ง์ (scoping)์ด ์๋, ํจ์ ๋ ๋ฒจ ๋ฒ์ ์ง์ ์ ๊ตฌํํ๋ค. ๋ฐ๋ผ์ ์์ ์์์ outerFunc๋ด์ ์ ์ ๋ ๋ณ์ ๋ ํด๋น ํจ์์ ์ค์ฝํ๊ฐ ๋ก์ปฌ์ด๋ฏ๋ก ํจ์ ์ธ๋ถ์์๋ ์ก์ธ์ค ํ ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ ์ผ๋ฐ์ ์ผ๋ก ํจ์ ์คํ์ด ๋๋๋ฉด ๋ก์ปฌ ๋ณ์๊ฐ ๋ ์ด์ ์กด์ฌํ์ง ์๊ฒ ๋๋ค. ๊ทธ๋ฌ๋ outerFunc ํจ์๊ฐ ๋ก์ปฌ ๋ณ์๋ฅผ ์ฐธ์กฐํ๋ innerFunc ๋ฅผ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ์ ์ฝ๋๋ ํฅ๋ฏธ๋กญ๋ค. outerFunc ๊ฐ ์คํ์ ๋ง์น ํ์๋ message ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์์๊น?
> var myFunc = outerFunc();
> myFunc();
'Hello, World!'
message ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ๋ณด๋ค์ํผ, outerFunc๋ innerFunc๋ฅผ ๋ฐํํ๊ณ myFunc์ ์ ์ฅํ๋ค. myFunc ๋ ํด๋ก์ ๊ฐ ๋์ด ์์ฑ ๋ ํ๊ฒฝ์ ๊ธฐ์ตํ๊ธฐ ๋๋ฌธ์, outerFunc ๊ฐ ์คํ๋ ๋ message ๋ณ์ ์ ๊ฐ์ ๊ธฐ์ตํ๋ค . ์ด๋ฐ ๊ด๊ณ๋ฅผ ๋ชจ๋ฅด๋ ์ํ์์ ํด๋ก์ ๋ฅผ ์ฌ์ฉํ์ ๊ฐ๋ฅ์ฑ์ด ์์ผ๋ ์์๋์!
2. For loops: ์ผ๋ฐ์ ์ธ ์ค์
for ๋ฃจํ ๋ด์์ ํจ์๋ฅผ ์คํํ ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊ฒฝํ์ด ์์ ๊ฒ์ด๋ค. ์ด ๋ฌธ์ ๊ฐ ๋์๊ฒ ์ฒ์ ์ผ์ด ๋ฌ์ ๋ ๋๋ ๋๋ ค์น์ฐ๊ณ ์ถ์๋ค. ์๋ ์์ ๋ฅผ ์ดํด๋ณด์.
var names = ['Locke', 'Franklin', 'Smith', 'Mises'];
var logName = function(name) {
console.log(name);
};
var name;
for (var i=0; i < names.length; i++) {
name = names[i];
setTimeout(function(){
logName(name);
}, 1000);
}
์์ ์ฝ๋์์๋ names ์ด๋ผ๋ ๋ฐฐ์ด์ ๋ง๋ค์ด ๋ค ๊ฐ์ ์ด๋ฆ ๋ชฉ๋ก์ ์ ์ฅํ๋ค. name์ ๋งค๊ฐ ๋ณ์๋ก ๋ฐ๊ณ ๊ธฐ๋กํ๋ logName ํจ์๋ฅผ ๋ง๋ค์๋ค. ๊ทธ๋ฐ ๋ค์ names์ ๋ฐ๋ณตํ๋ฉฐ logName์ name์ ์ ๋ฌํ๊ณ , ํด๋น ํจ์๋ฅผ 1์ด ํ์ ์คํํ๋ for loop๋ฅผ ๋ง๋ค์๋ค . ์ด ์์ ๊ฐ ์ ์์ ์ผ๋ก ๋์ํ๋ค๊ณ ์๊ฐํ ์๋ ์์ง๋ง ์ค์ ๋ก "Mises"๋ฅผ ๋ค ๋ฒ ๊ธฐ๋กํ๋ค. ๊ทธ ์ด์ ๋ ๋งค์ฐ ๊ฐ๋จํ๋ค. logName์ ์์ฑ๋ ํ๊ฒฝ์ ๊ธฐ์ตํ๋ ํด๋ก์ ์ด๋ค. for ๋ฃจํ์์ logName ๋ฐ๋ก ํธ์ถ ํ ๊ฒฝ์ฐ์ ๋ชจ๋ name์ ๊ธฐ๋กํ๋ค. ๊ทธ๋ฌ๋ ์ฐ๋ฆฌ๋ ๋์ ํ์ ์์์ ์ค์ ํ๊ณ ํด๋ก์ (setTimeout์ ๋ํ ์ฝ๋ฐฑ)๋ฅผ ๋ง๋ค๊ณ ์์ผ๋ฉฐ, ์ด ํด๋ก์ ๋ ํ๊ฒฝ์ ๊ธฐ์ตํ๊ณ ์๋ค. 1์ด๊ฐ ์ง๋ ๋ค, name ๋ณ์๊ฐ "Mises"๋ก ์ค์ ๋์๋ค. ๋ฐ๋ผ์ ๋จ์ํ "Mises"๋ฅผ ๋ค ๋ฒ ๊ธฐ๋กํ๋ ๊ฒ์ด๋ค. ์ด ๋ฌธ์ ๋ฅผ ์ด๋ป๊ฒ ํด๊ฒฐํ ์ ์์๊น? ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ํ ๊ฐ์ง ๋ฐฉ๋ฒ์ ๋ค๋ฅธ ํด๋ก์ ๋ฅผ ๊ตฌํํ๋ ๊ฒ์ด๋ค.
var names = ['Locke', 'Franklin', 'Smith', 'Mises'];
var logName = function(name) {
console.log(name);
};
var makeClosure = function(name) {
return function() {
logName(name);
}
};
for (var i=0; i < names.length; i++) {
var name = names[i];
setTimeout(makeClosure(name), 1000);
}
๊ทธ๋ฌ๋ ๋ถํ์ํ ํด๋ก์ ๋ฅผ ๋ง๋๋ ๊ฒ์ ์ข์ง ์๋ค. ์ฌ์ค, ์ํ๋ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ํจ์ฌ ๋ ์ข์ ๋ฐฉ๋ฒ์ด ์์ง๋ง for loop์ ํด๋ก์ ๋ฌธ์ ์ ํด๋ก์ ๋ก ์ด๋ป๊ฒ ํด๊ฒฐํ ์ ์๋์ง ์ค๋ช ํ๊ณ ์ถ์๋ค. ์์ ์ฝ๋๋ฅผ ์คํํ๋ฉด 1 ์ด ์ง์ฐ ํ 4 ๊ฐ์ name์ด ๊ฐ๊ฐ์ด ๊ธฐ๋ก๋์ด ์์๋๋ก ์๋ํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค. ์ฐ๋ฆฌ๊ฐ ํด์ผ ํ ์ผ์ name ๋ณ์๊ฐ ์์ฑ ๋ ๋๋ถํฐ '๊ธฐ์ตํ๋' ํด๋ก์ ๋ฅผ ๋ฐํ ํ๋ makeClosure ํจ์๋ฅผ ๋ง๋๋ ๊ฒ์ด ์๋ค. ํด๋ก์ ๋ ์ฆ์ ๋ง๋ค์ด ์ง๋ฏ๋ก ๊ฐ name ์ ๊ฐ์น๋ฅผ ๊ธฐ์ตํ๋ค.
3. ๋ชจ๋ ํจํด
๋ง์ ๊ฐ๋ฐ์๋ค์ด ์๋ฐ์คํฌ๋ฆฝํธ ํด๋ก์ ์ ๊ธฐ๋ฐํ ๋ชจ๋ ํจํด์ ์ฌ์ฉํ๋ค. ์ด ๋งํฌ์์ ๋ชจ๋ ํจํด์ ๋ํด ์์ธํ ์ดํด๋ณผ ์ ์์ง๋ง, ์ฌ๊ธฐ์ ๊ธฐ๋ณธ๊ณผ ํด๋ก์ ๋ฅผ ์ด๋ป๊ฒ ๊ตฌํํ๋์ง์ ๋ํด ์ค๋ช ํ๊ณ ์ ํ๋ค. ๋ชจ๋ ํจํด์ ์ฌ์ฉํ๋ ๋ชฉ์ ์ ์ฝ๋๋ฅผ ์ ๋ฆฌํ๊ณ , ๊ธ๋ก๋ฒ ์ค์ฝํ๋ฅผ ๊นจ๋ํ๊ฒ ์ ์งํ๋ฉฐ, ๋ชจ๋ ์ธ๋ถ์์ ์ ๊ทผํด์๋ ์ ๋๋ private ์ฝ๋๋ฅผ ์ ์งํ๋ ๊ฒ์ด๋ค. ๋ชจ๋ ํจํด์ ๋ค์๊ณผ ๊ฐ๋ค.
var module = (function(){
var localVar = 1913;
var localFunc = function() {
return localVar;
}
var otherLocalFunc = function(num) {
localVar = num;
}
return {
getVar: localFunc,
setVar: otherLocalFunc
}
})();
์ ์์ ์์ ์ต๋ช ํจ์ ์์ ๋จ์ผ ํ๊ฒฝ์ ๋ง๋ค์๋ค. ์ด ํ๊ฒฝ์๋ ๋ก์ปฌ ๋ณ์ localVar ๋ฐ ๋ก์ปฌ ํจ์ ํํ์ localFunc๊ฐ ํฌํจ ๋๋ค. ์ด ๋ณ์ ์ค ์ด๋ ๊ฒ๋ ์ต๋ช ํจ์ ์ธ๋ถ์์ ์ ๊ทผ ํ ์ ์์ผ๋ฏ๋ก ์ ์ญ ๋ค์ ์คํ์ด์ค๋ฅผ ๊นจ๋ํ๊ฒ ์ ์งํ ์ ์๋ค. ์ต๋ช ํจ์ ์ธ๋ถ์์ ์ ๊ทผํ ์ ์๋ ๋ฐฉ๋ฒ์ ์ต๋ช ํจ์์ ์ํด ๋ฐํ๋์ด์ผํ๋ค. ์ ์์์ ๋ณผ ์ ์๋ฏ์ด, localFunc์ ๊ฐ์ผ๋ก ๊ฐ์ง๋getVar๋ผ๋ key์, otherLocalFunc๋ฅผ ๊ฐ์ผ๋ก ๊ฐ์ง๋ setVar ๋ผ๋ key ๊ฐ์ง ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค. ์ด ํจํด์ ๋ํ ์ข์ ์ ์ ๋ชจ๋์ state๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์๋ช ๋์ ์ง์๋๋ค. ์ด๊ฒ์ localVar๋ฅผ ์ธ๋ถ์์ ์ง์ ์ก์ธ์ค ํ ์ ์์ง๋ง, ๋ฐํ๋ ํจ์๋ ์ฌ์ ํ์ด ๋ณ์์ ์ ๊ทผ ํ ์ ์์์ ์๋ฏธํ๋ค. ์์ ์ฝ๋๋ฅผ ์ฌ์ฉํ์ฌ ์๋ ์์ ๋ฅผ ์ดํด๋ณด๋ผ.
console.log(module.getVar());
> 1913
module.setVar(1776);
console.log(module.getVar());
> 1776
์๋ฐ์คํฌ๋ฆฝํธ์์ private ๋ณ์ localVar๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ์๋ฎฌ๋ ์ด์ ํ๊ณ , ์ ์ญ ๋ค์ ์คํ์ด์ค๋ฅผ ๊นจ๋ํ๊ฒ ์ ์งํ๋ค . ์ฌ๊ธฐ์ ์ ์ผํ ์ ์ญ ๋ณ์๋ module ์ด๋ค. ์ด ๋ชจ๋ ๊ฒ์ ํด๋ก์ ๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌํํ๋ค. ์ด ๊ธ์ ๋ฒ์์ ํฌํจ๋์ง๋ ์์ง๋ง ์ด ํจํด์ IIFE (์ฆ์ ํธ์ถ ํจ์ ํํ์)๋ฅผ ์ฌ์ฉํ๋ค. ์ต๋ช ํจ์๊ฐ (function () {...}) () ๊ณผ ๊ฐ์ด ๊ดํธ๋ก ๋ฌถ์ฌ ์์์ ๋ณผ ์์๋ค. ๊ดํธ๊ฐ ์์ผ๋ฉด ์ด๊ฒ์ ๋จ์ํ ํจ์ ์ ์ ์ผ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ ๊ดํธ๋ฅผ ์ถ๊ฐํ๋ฉด (๋ค์ ๋์ค๋ ๊ดํธ์๋ ์ ์) ์ฆ์ ํธ์ถ ํจ์ ํํ์์ด ๋๋ค. ์ด์ ๋ํ ์์ธํ ๋ด์ฉ์ ์ฌ๊ธฐ๋ฅผ ์ฐธ์กฐ ํ๋ผ.
4. ๋๋ค๋ฅธ ์์
์ข ๋ ์ค์ฉ์ ์ธ ์๊ฐ ์๋ค. ์ฆ์์์ ํจ์๋ฅผ ๋ง๋ค๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด๋ณด์. ํจ์ ํฉํ ๋ฆฌ(ํจ์๋ฅผ ๋ง๋๋ ํจ์)๋ฅผ ๋ง๋ค ์ ์๋ค. ํจ์ ํฉํ ๋ฆฌ์ ๊ฒฐ๊ณผ ํจ์๋ ์์ฑ๋ ํ๊ฒฝ์ ๊ธฐ์ตํ๋ ํด๋ก์ ์ด๋ค.
var functionFactory = function(num1) {
return function(num2) {
return num1 * num2;
}
}
์์ functionFactory ํจ์์ ํ๋์ ์ซ์๋ฅผ ๋๊ธธ ์ ์๋ค. ๊ทธ๋ฐ ๋ค์ functionFactory๋ ์๋ ์ ๋ฌ ๋ num1 ๊ฐ์ ๊ธฐ์ตํ๋ ํด๋ก์ ๋ฅผ ๋ฆฌํดํ๋ค . ๊ฒฐ๊ณผ ํจ์๋ ๊ธฐ์กด num1์ ํด๋ก์ ํธ์ถ ์ ์ ๋ฌ ๋ num2 ๊ฐ์ ๊ณฑํ๋ค .
var mult5 = functionFactory(5);
var mult10 = functionFactory(10);
์์ ๊ฐ๋จํ ํจ์๋ ์๋ก์ด ํจ์ mult5 ๋ฐ mult10์ ๋ง๋ ๋ค . ์ด์ 5 ๋๋ 10์ ๊ณฑํ๋ ค๋ ์ซ์๋ฅผ ์ ๋ฌํ์ฌ ์ด๋ฌํ ํจ์ ์ค ํ๋๋ฅผ ํธ์ถ ํ ์ ์๋ค. ์ด์ ๊ฒฐ๊ณผ๋ฅผ ์์ ํ ์ ์๋ค.
> mult5(3)
15
> mult5(5)
25
> mult10(3)
30
> mult10(5)
50
์ด ๊ฐ์ด๋๊ฐ ์ ์ฉํ๋ค๊ณ ์๊ฐ๋๋ฉด ์๋์ ์๋ ค์ฃผ๊ธฐ ๋ฐ๋๋ค. ๋ํ ์ค๋ฅ๋ฅผ ๋ฐ๊ฒฌ ํ๊ฑฐ๋ ๋ ๋ ํนํ ์์ ๋ฅผ ์ ๊ณต ํ ์ ์๋ ๊ฒฝ์ฐ ์๊ฒฌ์ ๋ณด๋ด์ฃผ๊ธฐ ๋ฐ๋๋ค.