Understand Closures in JavaScript - Lee-hyuna/33-js-concepts-kr GitHub Wiki
์๋ฐ์คํฌ๋ฆฝํธ ํด๋ก์ ธ ์ดํด
ํด๋ก์ ๋ ๋ณต์กํ์ง ์์ต๋๋ค. ๋จ 10๋ถ๋ง์ ํด๋ก์ ์ ๊ธฐ์ด๋ฅผ ๋ฐฐ์ฐ๊ณ ์ดํด ํด๋ด ์๋ค.
ํด๋ก์ ๋ ๋ฌด์์ ๋๊น?
ํด๋ก์ ๋ ๋ชจ๋ ๊ฐ๋ฐ์๊ฐ ์๊ณ ์ดํดํด์ผ๋๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ์ฃผ์ ์ธก๋ฉด์ ๋๋ค. ์ค๋๋ ์ ๊ธ์ ํด๋ก์ ํ๋ฉด๋ง ํ์ด ๋ณด์์ง๋ง ์๋ฐ์คํฌ๋ฆฝํธ์์ ํด๋ก์ ๊ฐ ๋ฌด์์ธ์ง ์ด๋ป๊ฒ ์๋ํ๋์ง์ ๋ํ ์ข์ ์์ด๋์ด๋ฅผ ์ค ๊ฒ์ ๋๋ค. ๋ฐ์ด ๋ค์ด๊ฐ ๋ด ์๋ค.
์ฐ๋ฆฌ๋ ํด๋ก์ ์ ๋ํ ๋ ๊ฐ์ง ๊ต๊ณผ์ ์ ์๋ฅผ ์ดํด ๋ณผ ๊ฒ์ ๋๋ค.
์ ์ #1
ํด๋ก์ ๋ ์ค์ฝํ๊ฐ ๋ซํ ํ์๋ ์์ ์ค์ฝํ์ ์ ๊ทผ ํ ์ ์๋ ํจ์์ ๋๋ค.
์ ์ #2
ํด๋ก์ ๋ ํจ์์ ํด๋น ํจ์๊ฐ ์ ์ธ๋ 'lexical environment'์ ์กฐํฉ์ ๋๋ค.
์ข์ต๋๋ค. ๊ทธ๋ฌ๋ ์ค์ ๋ก ๋ฌด์์ ์๋ฏธํ ๊น์?
๋จผ์ ์๋ฐ์คํฌ๋ฆฝํธ์ ์ค์ฝํ๋ฅผ ์ดํดํด์ผ๋ฉ๋๋ค. ์ค์ฝํ๋ ๋ณธ์ง์ ์ผ๋ก ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋ณ์์ ์๋ช ์ ๋๋ค. ๋ณ์๊ฐ ์ ์ ๋ ์์น๋ ํด๋น ๋ณ์์ ์ง์ ์๊ฐ๊ณผ ํ๋ก๊ทธ๋จ์ ํจ์์ ์ ๊ทผํ๋๋ฐ ํฐ ์ญํ ์ ํฉ๋๋ค.
์๋ฅผ ๋ค์ด ๋ด ์๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ก ํจ์๋ฅผ ์์ฑํ๋ฉด ํจ์ ๋ด๋ถ ๋ฐ ์ธ๋ถ์์ ์์ฑ๋ ๋ณ์์ ์ ๊ทผ ํ ์ ์์ต๋๋ค.
ํจ์ ๋ด์์ ์์ฑ ๋ ๋ณ์๋ ๋ก์ปฌ๋ก ์ ์๋ ๋ณ์์
๋๋ค. ์ง์ญ๋ณ์๋ ์ ์๋ ํจ์(์ค์ฝํ) ๋ด์์๋ง ์ ๊ทผ ํ ์ ์์ต๋๋ค. ์๋ ์์ ์์ ํจ์ ์ธ๋ถ์ words
๊ฐ์ ๊ธฐ๋กํ๋ ค๊ณ ํ๋ฉด ์ฐธ์กฐ ์ค๋ฅ๊ฐ ๋ฐ์ ํจ์ ์ ์ ์์ต๋๋ค. words
๋ ์ง์ญ ์ค์ฝํ๊ฐ ์ง์ ๋ ๋ณ์ ์ด๊ธฐ ๋๋ฌธ์
๋๋ค.
// Example of accessing variables INSIDE the function
// words is a LOCAL variable
function speak(){
var words = 'hi';
console.log(words);
}
speak(); // 'hi'
console.log(words); // Uncaught ReferenceError: words is not defined
์ด ์์ ์๋ ๋์กฐ์ ์ผ๋ก, ์ฐ๋ฆฌ๊ฐ ์ ์ญ ์ค์ฝํ์์ words
๋ฅผ ์ ์ํ๋ ๊ฒฝ์ฐ ๋ฌธ์์ ๋ชจ๋ ํจ์์ ์ ๊ทผ ํ ์ ์์ต๋๋ค.
// Example of accessing variables OUTSIDE the function
// words is a GLOBAL variable
var words = 'hi';
function speak(){
console.log(words);
}
speak(); // 'hi'
console.log(words); // 'hi'
Nested Functions
ํ ํจ์๋ฅผ ๋ค๋ฅธ ํจ์ ์์ ์ค์ฒฉํ๋ฉด ์ด๋ป๊ฒ ๋ฉ๋๊น?
์ด ์์ ๊ฐ ์ฌ๋ฏธ์์ด์ง๊ธฐ ๋๋ฌธ์ ๋ค์ ์์ ๋ฅผ ๋ฐ๋ผ๊ฐ ๋ณด์ญ์์ค.
Chrome์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ฝ์์ฐฝ ์ฌ๋ ๋ฐฉ๋ฒ
[WINDOWS] : Ctrl + Shift + J
[MAC] : Cmd + Opt + J
cool. ์ด์ ์๋ ์ฝ๋๋ฅผ ๋ณต์ฌํ์ฌ ์ฝ์์ฐฝ์ ๋ถ์ฌ ๋ฃ์ต๋๋ค. ์ฐ๋ฆฌ๋ speak
๋ผ๋ ํจ์๋ฅผ ๋ง๋๋ ๊ฒ์
๋๋ค. speak
๋ logIt
์ด๋ผ๋ ํจ์๋ฅผ ๋ฐํํฉ๋๋ค. ๋ง์ง๋ง์ผ๋ก logIt
์ words
์ ๊ฐ์ ์ฝ์์ ๊ธฐ๋กํฉ๋๋ค. ์ด ๊ฒฝ์ฐ ์ฝ์์ 'hi'
๋ฅผ ๊ธฐ๋กํฉ๋๋ค.
function speak() {
return function logIt() {
var words = 'hi';
console.log(words);
}
}
์ฝ์์ ๋ณต์ฌ ํ ํ ๋ณ์๋ฅผ ๋ง๋ค์ด speak
ํจ์๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ํ ๋นํฉ๋๋ค:
var sayHello = speak();
์ด์ ์ฐ๋ฆฌ๋ ๋ณ์๋ฅผ ๋ถ๋ฅด์ง๋ง ๋ด๋ถ ํจ์์ ๋ถ๋ฌ๋ค์ด์ง ์์๋ sayHello
์ ๊ฐ์ด ๋ฌด์์ธ์ง ์ ์ ์์ต๋๋ค:
sayHello;
// function logIt() {
// var words = 'hi';
// console.log(words);
// }
์์๋๋ก sayHello
๋ ๋ฐํ๋ ๋ด๋ถ ํจ์๋ฅผ ์ฐธ์กฐํฉ๋๋ค. ์ด๊ฒ์ ์ฝ์์์ sayHello()
๋ฅผ ์คํํ๋ฉด logIt()
ํจ์๋ฅผ ํธ์ถํ๊ณ ์คํํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค:
sayHello();
// 'hi'
ํจ๊ณผ๊ฐ ์์ด! ๊ทธ๋ฌ๋ ์ด๊ฒ์ ํน๋ณํ ๊ฒ์ ์๋๋๋ค. ํ ์ค์ ์ฝ๋๋ฅผ ์์ง์ฌ์ ์ด๋ค ๋ณํ๊ฐ ์๋์ง ๋ด
์๋ค. ์๋ ์์ ๋ฅผ ์ดํด๋ณด์ญ์์ค.
๋ณ์ words
์ ์ธ์ ๋ด๋ถํจ์์์ ์ธ๋ถspeak()
ํจ์๋ก ์ฎ๊ฒผ์ต๋๋ค:
function speak() {
var words = 'hi';
return function logIt() {
console.log(words);
}
}
์ด์ ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ณ์๋ฅผ ์ ์ธํ๊ณ speak
ํจ์์ ํ ๋นํฉ๋๋ค :
var sayHello = speak();
์ด์ sayHello
๋ณ์๊ฐ ๋ฌด์์ ์ฐธ์กฐํ๋์ง ์ดํด ๋ณด๊ฒ ์ต๋๋ค :
sayHello
// function logIt() {
// console.log(words);
// }
Uh oh. words
๋ณ์ ์ ์๊ฐ ์์ต๋๋ค. ํจ์๋ฅผ ํธ์ถํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น์?
sayHello();
// 'hi'
์ฌ์ ํ ์๋ํฉ๋๋ค! ํด๋ก์ ์ ํจ๊ณผ๋ฅผ ๋ฐฉ๊ธ ๊ฒฝํํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
ํผ๋์ค๋ฌ์ด๊ฐ์? ๊ด์ฐฎ์ต๋๋ค. ํด๋ก์ ์ ์๋ฅผ ๋ค์ ์๊ฐํด๋ณด์ญ์์ค.
ํด๋ก์ ๋ ๋ฒ์๊ฐ ๋ซํ ํ์๋ ์์ ์ค์ฝํ์ ์ ๊ทผ ํ ์์๋ ํจ์์
๋๋ค.
์ด ๊ฒฝ์ฐ speak()
ํจ์์ ์ค์ฝํ๊ฐ ๋ซํ์ต๋๋ค. ์ด๊ฒ์ var words = 'hi'
๋ ์ฌ๋ผ์ ธ์ผ ํจ์ ์๋ฏธํฉ๋๋ค. ๊ทธ๋ฌ๋ ์๋ฐ์คํฌ๋ฆฝํธ์๋ ํด๋ก์ ๋ผ๋ ๋ฉ์ง ์์ ๊ฐ๋
์ด ์์ต๋๋ค. ๋ด๋ถ ํจ์๋ ์์ฑ๋ ๋ฒ์์ ๋ํ ์ฐธ์กฐ๋ฅผ ์ ์งํฉ๋๋ค. ์ด๋ ๊ฒํ๋ฉด speak()
๊ฐ ๋ซํ ํ์๋ logIt ()
ํจ์๊ฐ words
๋ณ์์ ๊ณ์ ์ ๊ทผ ํ ์ ์์ต๋๋ค.
function speak() {
var words = 'hi';
return function logIt() {
console.log(words);
}
}
์๋ฐ์คํฌ๋ฆฝํธ์ ๋ชจ๋ ํจ์์๋ ํด๋ก์ ๊ฐ ์์ต๋๋ค. ์ด ๊ธฐ๋ฅ์ ์๋์ํค๊ธฐ ์ํด ํจ์์ ๋ํด ๋ช ์์ ์ผ๋ก ํ ํ์๋ ์์ต๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ์ ์ผ๋ถ์ผ ๋ฟ์ ๋๋ค.
Example #2
๋ค๋ฅธ ์๋ฅผ ์ดํด ๋ณด๊ฒ ์ต๋๋ค. ์กฐ๊ธ ๋ ๋ณต์กํฉ๋๋ค. ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค :
function name(n) {
return function(a) {
return `${n} likes ${a}`;
};
}
ํ๋์ ๋งค๊ฐ ๋ณ์๋ฅผ ์ฌ์ฉํ๊ณ ๋ค๋ฅธ ๋งค๊ฐ ๋ณ์๋ฅผ ์ฌ์ฉํ๋ ์ต๋ช
ํจ์๋ฅผ ๋ฐํํ๋ name
ํจ์๊ฐ ์์ต๋๋ค. ๋ด๋ถ ํจ์์ ๊ฒฐ๊ณผ๋ ๋ฌธ์์ด์ ๋ฐํํฉ๋๋ค.
name
ํจ์๋ฅผ ๋ ๋ฒ ํธ์ถ ํด๋ด
์๋ค. ํ๋๋ John์ด๋ผ๋ ์ด๋ฆ์, ๋ค๋ฅธ ํ๋๋ Cindy๋ฅผ ์ ๋ฌํฉ๋๋ค.
var j = name('John');
var c = name('Cindy')
์ด์ j
๊ฐ ๋ฌด์์ ์ฐธ์กฐํ๋์ง ์ ํํ ์ ์ ์์ต๋๋ค :
j;
// function (a) {
// return `${n} likes ${a}`;
// }
๋๋จํฉ๋๋ค! ์ด์ ์์ ์์ ํด๋ก์ ๋ก ์ธํด ํจ์๊ฐ ์ฌ์ ํ ์์ ์ค์ฝํ์์ n
๋ณ์์ ์ ๊ทผ ํ ์ ์์ด์ผ ํ๋ค๋ ๊ฒ์ ์๊ณ ์์ต๋๋ค. ํจ์๋ฅผ ํธ์ถ ํ ๋ ๊ฐ์ ์ ๋ฌํ๋ฉด๋ฉ๋๋ค.
์๋ํด ๋ด
์๋ค :
j('dogs'); // 'John likes dogs'
c('cats'); // 'Cindy likes cats'
์๋ํฉ๋๋ค! ํด๋ก์ ๋ก ์ธํด ์ด์ ์ ๋ซํ ์ค์ฝํ์ ๋ณ์๋ฅผ ์ฐธ์กฐํ๋ ํจ์๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ์คํํ ์ ์์ต๋๋ค.
๋ ๋ฐ์ ๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ํฉ๋๊น?
Check out: JavaScript: Understanding the Weird Parts
Closing Notes
ํด๋ก์ ์ ๊ธฐ๋ณธ ์ฌํญ์ด ์๋ฐ์คํฌ๋ฆฝํธ๋ก ์ด๋ป๊ฒ ์๋ํ๋์ง ์ดํดํ ์ ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ์ด๊ฒ์ ๋จ์ง ๋น์ฐ์ ์ผ๊ฐ ์ผ๋ฟ์ ๋๋ค. ์ด์ ํด๋ก์ ์ ๋ ๋ณต์กํ๊ณ ์ค์ฉ์ ์ธ ์์ ๋ํด ๋ฐฐ์ธ ์ง์์ด ์์ต๋๋ค.