๋ค์ด๊ฐ๋ฉด์
์ด๋ฒ ๊ธ์, closure์ ๋ํ ์คํด ๊ฒฝํ๊ณผ ์์๊ฐ๋ฉด์ ์๊ธด ๊ถ๊ธ์ฆ๋ค์ ์ ๋ฆฌํ๋ ๊ธ์ด๋ค. ์ด ๊ธ์ ์๋ฆฌ์ฆ๋ก ์์ฑ ๋์ด์ง ์์ ์ด๋ค. ์ง๊ธ ๊ธ์ ๋ ์์ปฌ ์ค์ฝํ์ ํด๋ก์ ๊ฐ๋ ์ ์ฐ๊ฒฐ์ ์ ์ค์ฌ์ผ๋ก ํด๋ก์ ๊ฐ ๊ด์ฐฐ ๋๋ ์ํ์ ์๋ ์ํ๋ฅผ ๊ตฌ๋ถํ ํด๋ก์ ๊ฐ๋ ์ ์ด์ ์ ๋ง์ถ์๋ค. ์ ์ญ ์ปจํ ์คํธ ๋ด๋ถ๋ฅผ ํด๋ถ ํ๋ ๊ธ์ด ๋ค์ ๊ธ์ด ๋ ๊ฒ์ด๋ค.
์คํ์์ค ์ฝ๋์์ ์ ์ ๊ฐ Drawer๋ฅผ ํ ๊ธ ํ๋ ์ฝ๋ฐฑ ํจ์์ฒ๋ฆฌ์์ ์ํ๊ฐ ๋ณ๊ฒฝ๋์ง ์๋ ๊ฒฝ์ฐ๊ฐ ์์๋๋ฐ, ์ด ์์ธ์ ํด๋ก์ ๋ก ์ธํด ์ํ๊ฐ์ด ์บก์ณ๋ง ๋์๋ค๊ณ ์๊ฐํ์ฌ ๋ฌธ์ ์ ์๋ฅผ ์ ์ด์ ์๋ชปํ ์ ์ด ์์๋ค. ์ด ๋ ๋ด๊ฐ ์ ์ํ ์บก์ณ๋ง์ด ์์ ์๋ชป ๋์๋ ๊ฒ์ด๋ค.
ํด๋ก์ ์ ๋ํด ์ ํํ๊ฒ ์๊ณ ์์๋๋ผ๋ฉด, ๋ฌธ์ ํด๊ฒฐ์ ๋ ๋นจ๋ฆฌ ๋๋ฌ ํ์ ๊ฒ์ด๋ค.
ํด๋ก์ ํ์ ํ์ ํ๊ธฐ
๋จผ์ ํด๋ก์ ํ์์ด ์ผ์ด๋์ง ์์ ๊ฒฝ์ฐ ์ด๋ค.
let str0 = "str0";
function func1() {
let str1 = "str1";
console.log(str0, str1, str2);
}
function func2() {
let str2 = "str2";
console.log(str0, str1, str2);
}
console.log(str0, str1, str2);
func1();
func2();
์๋ ์ด๋ฏธ์ง๋ ํฌ๋กฌ์ devtools์ ์คํ ์ปจํ ์คํธ ๊ธฐ์ค์ผ๋ก ๊ทธ๋ ค ๋ณด์๋ค. (๋ธ๋ผ์ฐ์ , IDE ๋ง๋ค scope์ ์ด๋ฆ์ด ์กฐ๊ธ์ฉ ๋ค๋ฅด๋ค.) ์ด๋ฏธ์ง์ ์ ์ผ ์ผ์ชฝ์ ์๋ container๊ฐ ์ฝ์คํ์ด๋ค. ํจ์๊ฐ ํธ์ถ ๋ ๋ ๋ง๋ค ์ฝ์คํ์ ์์ด๊ณ , ์คํ ์ปจํ ์คํธ๊ฐ ์์ฑ๋๋ค. ๊ฐ๊ฐ์ ์คํ ์ปจํ ์คํธ๋ ์ค์ฝํ๋ฅผ ๊ฐ์ง๋๋ฐ, ์ด ์ค์ฝํ๊ฐ ๋ฐ๋ก ๋ณ์๋ฅผ ์ฐธ์กฐํ ์ ์๋ ์ ํจ๋ฒ์์ ํด๋นํ๋ค.
func1() ๋ด์์ str0 ๋ฅผ ์ฐธ์กฐํ ์ ์๋ ๋ฐฉ๋ฒ์ ํ์ฌ ์คํ ๋๊ณ ์๋ ํจ์์ ์ ํจ ๋ฒ์ ๋ด์ ์๋ str0์ ์ฐพ๋๋ค.
์ ํจ ๋ฒ์์ ์์์ ํ์ฌ ๋ณด์ด๋ scope ๊ธฐ์ค์ผ๋ก local scope๋ถํฐ ์์ํ์ฌ ์์ผ๋ฉด global scope๋ก ์ฌ๋ผ๊ฐ์ ์ฐพ๋๋ค. ์ local str1์ด local scope์ ์ ์ฅ๋์ด ์๋์ง ๋ชจ๋ฅธ๋ค๋ฉด let, var, const ์ ์ ํจ๋ฒ์์ ๋ํ ์ ํ ์ง์์ด ํ์ํ๋ค. script scope์ str0์ด ์๊ธฐ ๋๋ฌธ์ str0์ ์ฐพ์ ์ ์๋ค.
ํ์ง๋ง func1()
์์ str2
๊ฐ์ ์ฐธ์กฐํ ์ ์๋ค. ์ด์ ๋ str2๋ func1() ์ ์ค์ฝํ์์๋ ์ฐพ์ ์๊ฐ ์๋ค.
๊ทธ๋ผ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํด ๋ณด์.
func2() ํธ์ถ์ func1()๋ด๋ก ์ฎ๊ฒจ ๋ณธ๋ค.
let str0 = "str0";
function func1() {
let str1 = "str1";
console.log(str0, str1, str2);
func2();
}
function func2() {
let str2 = "str2";
console.log(str0, str1, str2);
}
console.log(str0, str1, str2);
func1();
func2()๋ฅผ func1()์์ ํธ์ถ ํ๊ธฐ ๋๋ฌธ์ str1์ ์ฐธ์กฐ ํ ์ ์์ ๊ฒ ๊ฐ์ง๋ง, func2()๋ผ๋ ํจ์์ค์ฝํ๋ฅผ ๊ฐ์ง ์๋ก์ด ์ ํจ๋ฒ์๊ฐ ์์ฑ๋ ์๊ฐ, func2()์ ์ ํจ๋ฒ์๋ func1()์ ์ ํจ๋ฒ์์๋ ๋ค๋ฅด๋ค. str1์ ์ฐธ์กฐ ํ ์ ์๋ค.
์ด์ ํด๋ก์ ์ธ ๊ฒฝ์ฐ๋ฅผ ์ดํด๋ณด์.
export function func1() {
const func2 = () => {
let str2 = "str2";
console.log(str1, str2); //"str1str2"
return str1 + str2;
};
let str1 = "str1";
console.dir(func2);
// console.log(str1, str2)
func2();
}
func1();
scope์ closure๊ฐ ์๋ก ์์ฑ์ด ๋์๋ค. ์ฆ ์ฐธ์กฐํ ์ ์์๋ str1์ func2ํจ์๋ฅผ ์ ์ํ ์์น๋ฅผ func1() ๋ด๋ก ๋ณ๊ฒฝํ๋ ์ฐธ์กฐํ ์ ์๊ฒ ๋์๋ค.
๋ค์์ ์ธํ
๋ฆฌ์ ์ด์์ ํด๋ก์ ๋ฅผ ๋๋ฒ๊น
ํ ํ๋ฉด์ด๋ค. console.dir(function2)
์์ [[Scopes]]
๋ด closure๋ก str1์ ์ฐธ์กฐ ํ๊ณ ์๋ค.
์ธ๋ถ ํจ์ func1()์ ์คํ ์ปจํ ์คํธ๊ฐ ์ข ๋ฃ๋์ด๋ ๋ด๋ถ ํจ์ func2()์ ์คํ ์ปจํ ์คํธ๊ฐ ์ข ๋ฃ๋์ง ์์๊ธฐ ๋๋ฌธ์, func2()์ ์คํ ์ปจํ ์คํธ๋ ์ฌ์ ํ ์ด์ ์๊ณ ,
ํด๋ก์ ์ ๊ฐ๋ ์ค์์ ๋ด๋ถ ํจ์๊ฐ ์คํํ ๋์ ๋ณ์์ ํ๊ฒฝ์ ๊ธฐ์ตํด์ ๋ ๋ฆฝ์ ์ธ ํด๋ก์ ๋ฅผ ๊ฐ๊ฒ ๋๋ค๋ ๋ง์ด ์๋๋ฐ, ํน์ ์์ ์ ๊ฐ์ ๋ณด์กดํ๋ค๊ณ ์๊ฐํ๋ค. ๋ด๊ฐ ์ฌํ ์คํดํ ํด๋ก์ ์ ๊ฐ๋ ์ด์๋ค. ์บก์ณ๋ง ํน์ ์ค๋ ์ท์ ์๋ฏธ๋ก ์๋ชป ์ดํด ํ์ฌ ๊ฐ์ด ๋ณ๊ฒฝ ๋์ง ์๋ ๋ค๊ณ ์๊ฐํ์๋ค. ํด๋ก์ ์ ์ํด ์บก์ฒ๋๋ ๊ฒ์ ๋ณ์ ์์ฒด์ "๊ฐ"์ด ์๋๋ผ, ๋ณ์์ ๋ํ "์ฐธ์กฐ" ์ด๋ค. ๋ฐ๋ผ์ ํด๋ก์ ๋ด๋ถ์์ ์ฐธ์กฐํ๋ ๋ณ์์ ๊ฐ์ด ๋ณ๊ฒฝ๋๋ฉด, ํด๋ก์ ๋ฅผ ํตํด ์ ๊ทผํ ๋ ๋ณ๊ฒฝ๋ ๊ฐ์ด ๋ฐ์๋๋ค. You Don't Know JS ์ฑ ์์๋ ํด๋ก์ ๋ฅผ "๋ผ์ด๋ธ ๋งํฌ"๋ก ํํ ํ๋ค. ์ด์ ์ ๋ผ์ด๋ธ ๋งํฌ์ธ์ง ์ดํด๊ฐ ๊ฐ๋ค.
์นด์ผ ์ฌ์จ ์ฑ ์ ๋ณด๊ณ ์๋ ์ค, ์๋์ ๊ฐ์ ์์๊ฐ ์์๋ค. ์ด๊ฑด ํด๋ก์ ๋ฅผ ํฌํจํ๊ณ ์๋๊ฐ?
let hits;
{
let count = 0;
hits = function () {
count++;
console.log(count);
};
}
hits(); // 1
hits(); // 2
hits(); // 3
ํจ์ ๋ด์์ ์ฌ์ฉํ count
๋ณ์๋ ํจ์ ๋ฐ์ ์ค์ฝํ์์ ์ ์๋ count๋ฅผ ์ฐธ์กฐ ํ๊ณ ์๋ค.
๊ทธ๋ฐ๋ฐ ํจ์ ๋ฐ์ ์ค์ฝํ๊ฐ ํจ์ ์ค์ฝํ๊ฐ ์๋ ๋ธ๋ญ ์ค์ฝํ ์ด๋ค.
๋๋ฒ๊น
ํด๋ณด๋ฉด hits
ํจ์์ ์ค์ฝํ์๋ closure๊ฐ ์๋ค.
๊ทธ๋ฐ๋ฐ ์ด๊ฒ๋ ํด๋ก์ ๋ผ๊ณ ๋ณผ ์ ์๋๊ฐ?
๊ทธ๋ ๋ค๊ณ ํ๋ค. ํด๋ก์ ์ ์ธ๋ถ ์ค์ฝํ๋ ์ผ๋ฐ์ ์ผ๋ก ํจ์์์ ์ ๋ํ์ง๋ง, ๋ฐ๋์ ํจ์ ์ค์ฝํ์ผ ํ์๋ ์๋ค๋ ๊ฒ์ด๋ค. ๋ด๋ถ ํจ์๋ฅผ ๊ฐ์ธ๋ ์ธ๋ถ ์ค์ฝํ(ํจ์, ๋ธ๋ก)๊ฐ ์์ผ๋ฉด ํด๋ก์ ๊ฐ ์์ฑ๋๋ค.
[[Scopes]]
์ Closure์ด ์๋ Block์ด ์์ฑ๋์๋ค.
์ด๊ฒ์ Block Scope๋ฅผ ๊ฐ์ง๋ let, const, class, function ๋ฑ์ ์ ์ธ์ด ๋ธ๋ก ์ค์ฝํ๋ฅผ ์์ฑํ๊ธฐ ๋๋ฌธ์ด๋ค.
ํด๋ก์ ์ ์ํด ์ธ๋ถ ์ค์ฝํ์ธ Block Scope์ count ๋ณ์๋ฅผ ์ฐธ์กฐํ๊ณ ์๋ค.
๋ณด์ด์ง ์๋ ํด๋ก์
์๋ฌด๋ ์๋ ์ฒ์์ ๋๋ฌด ํ ๊ทธ๋ฃจ๊ฐ ์ฐ๋ฌ์ก์ง๋ง, ๊ทธ ๋๊ตฌ๋ ์๋ฆฌ๋ฅผ ๋ฃ์ง ๋ชปํ๋ค๋ฉด ์๋ฆฌ๋ ๋ ๊ฒ์ธ๊ฐ?
ํด๋ก์ ๋ฅผ ๊ด์ฐฐ ํ ์ ์๋ ๊ฒฝ์ฐ๋ ์๋ค.
๋ค์๊ณผ ๊ฐ์ ์๋ฅผ ๋ณด์.
function say(myName) {
let greeting = "Hello, ";
function inner() {
console.log(greeting + myName);
}
inner();
}
say("Hyunsu");
ํด๋ก์ ๋ฅผ ๊ด์ฐฐ ํ ์ ์๋?
inner()
ํจ์ ๋ด์์ ์ธ๋ถ ์ค์ฝํ์ธsay()
ํจ์์ ์ ์๋greeting
๊ณผmyName
์ ์ฐธ์กฐ ํ๊ณ ์์ผ๋ ํด๋ก์ ๊ฐ ์์ฑ ๋๋ค๊ณ ์คํด ํ ์ ์๋ค.- ์ฌ๊ธฐ์ ๊ด์ฐฐ ๋๋ ๊ฒ์ ํด๋ก์ ๊ฐ ์๋ ๋ ์์ปฌ ์ค์ฝํ ์ด๋ค.
- ๊ทธ ์ด์ ๋
inner()
ํจ์๋ฅผ ํธ์ถํ ์์น๊ฐgeeting
๊ณผmyName
์ ์ฐธ์กฐ ํ ์ ์๋ ๋์ผ ์ค์ฝํ ์ด๋ค. - ๊ทธ๋์ ํด๋ก์ ๋ฅผ ์ง์ํ์ง ์๋ ์ธ์ด์์๋ ๋ ์์ปฌ ์ค์ฝํ๋ฅผ ๊ฐ์ง ์ธ์ด๋ฉด ๋๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ง๊ฒ ๋๋ค.
๋๋ฒ์งธ ์์ด๋ค.
var students = [
{ name: "Joo", score: 80 },
{ name: "Jin", score: 70 },
{ name: "Kim", score: 60 },
{ name: "Park", score: 50 },
{ name: "Lee", score: 40 },
{ name: "Choi", score: 30 },
];
function getFirstStudent() {
return function firstStudent() {
return students[0].name;
};
}
let student = getFirstStudent();
console.log(student());
- getFirstStudent() ํจ์์์ ๋ฆฌํด์ ํจ์๋ก ํ๊ณ ๋ด๋ถ ํจ์ ํธ์ถ๊น์ง ํ๋ค.
- ๊ทธ๋ฐ๋ฐ ํด๋ก์ ๋ ๊ด์ฐฐ๋์ง ์๋๋ค.
- ์ด์ ๋ ์ฐธ์กฐํ students ๋ณ์์ ์ ์๋ ์์น๊ฐ ์ต์์์ธ ๊ธ๋ก๋ฒ ์ค์ฝํ์ด๋ค.
- ์ด๋ค ํจ์์์๋ students ์ฐธ์กฐ๊ฐ ๊ฐ๋ฅํ๋ค. ๊ทธ ์ด์ ๋ ํด๋ก์ ๊ฐ ์๋๋ผ ๋ ์์ปฌ ์ค์ฝํ ์ด๊ธฐ ๋๋ฌธ์ ์ด๋ค ํจ์์์๋ ์ ์ญ ๋ณ์์ ์ ๊ทผํ ์ ์๋ค.
์ธ๋ฒ์งธ ์์ด๋ค.
function lookupStudent(studentId) {
return function nobody() {
let msg = "Nobody here";
console.log(msg);
};
}
let student = lookupStudent(112);
student(); // Nobody here
- studentId ๋ฅผ ์ธ์๋ก ๋ฐ์ nobody() ํจ์๋ฅผ ๋ฆฌํดํ๋ค.nobody ํจ์๋ ์ธ๋ถ ์ค์ฝํ์ ์๋ studentID๋ฅผ ์ฐธ์กฐํ์ง ์๋๋ค.
- lookupStudent() ํจ์ ์คํ ํ studentId๋ฅผ ์ด๋ค ์ค์ฝํ์์๋ ์ฐธ์กฐํ์ง ์๊ธฐ ๋๋ฌธ์ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋์์ด ๋๋ค.
์ด๋ก์จ ๋์ถ ํ ์ ์๋ ํด๋ก์ ์ ์ ์๋ ๋ค์๊ณผ ๊ฐ๋ค.
ํจ์๊ฐ ์ธ๋ถ ํจ์ ์ค์ฝํ์ ๋ณ์๋ฅผ ์ฌ์ฉํ๋ฉด์, ๊ทธ ๋ณ์์ ์ ๊ทผ ๊ฐ๋ฅํ์ง ์์ ๋ค๋ฅธ ์ค์ฝํ์์ ํจ์๊ฐ ํธ์ถ๋๋ ๊ฒฝ์ฐ, ํด๋ก์ ๊ฐ ๊ด์ฐฐ ๋๋ค.
์ ๋ฆฌ
- ํด๋ก์ ์ ํต์ฌ์
- ๋ฐ๋์ ํจ์์ ๊ด๋ จ ๋์ด์ผ ํ๋ค.
- ์ธ๋ถ ์ค์ฝํ์ ๋ณ์๋ฅผ ํ๋ ์ด์์ ๋ฌด์กฐ๊ฑด ์ฐธ์กฐํด์ผ ํ๋ค.
- ํจ์ ๋ด์์ ์ฐธ์กฐํ๋ ค๋ ๋ณ์๊ฐ ์์ ๋, ํจ์ ํธ์ถ์ ๊ทธ ๋ณ์๊ฐ ์๋ ์ค์ฝํ ์ฒด์ธ์ด ์๋ ๋ค๋ฅธ ์ค์ฝํ์์ ํจ์๋ฅผ ํธ์ถ ํด์ผ ํ๋ค.