ํ ๊ฑธ์ Closure ๋ด ๋ง (Javascript Closure)
Closure๊ฐ ๋ญ๋ฐ? ๐
: Javascript์์์ Closure๋ ๋ด๋ถ ํจ์๊ฐ ์ธ๋ถ ํจ์์ ์ง์ญ ๋ณ์์ ์ ๊ทผํ๊ณ ์์ ๋, ์ธ๋ถ ํจ์๊ฐ ์คํ์ด ๋๋์ ์ง์ญ ๋ณ์๊ฐ ์๋ฉธ๋์์ด์ผ ํจ์๋ ์ฌ์ ํ ๋ด๋ถ ํจ์์์ ์ ๊ทผ์ด ๊ฐ๋ฅํ ๋งค์ปค๋์ฆ์ ์๋ฏธํ๋ค.
์ฅ ๊ทธ๋์ Closure๊ฐ ๋ญ์ผ? ๐
๋ค์๊ณผ ๊ฐ์ ์ํฉ์์ ์ฐ๋ฆฌ๋ Closure๋ฅผ ๋ณผ ์ ์๋ค.
function makeFunc() {
var name = 'Think Thing';
function displayName() { // Closure ํ์ฑ
alert(name);
}
return displayName;
}
var myFunc = makeFunc(); // myFunc๋ณ์์ displayName์ ๋ฆฌํด
myFunc();
- ์ด ์์์์ makeFunc()์ ์คํ์ด ๋๋๋ฉด displayName() ํจ์๋ name ๋ณ์์ ์ ๊ทผํ ์ ์๊ฒ ๋ ๊ฒ ๊ฐ์ง๋ง, ์ค์ ๋ก๋ ํจ์๊ฐ ์ ์์ ์ผ๋ก ์คํ๋๋ ๋ชจ์ต์ ๋ณผ ์ ์๋ค.
์, ์ด๊ฑฐ var ์จ์ ๊ทธ๋ฐ๊ฑฐ๋ค
- ES6+์์ ์ถ๊ฐ๋ const์ let์ผ๋ก ๋ฐ๊ฟ์ ์คํํด๋ ๋๊ฐ์ด ์ ์์ ์ผ๋ก ์คํ์ด ๋๋ค.
โ๏ธ ์ด์๋(์ด๊ฑฐ ์ ๋์๊ฐ?)
Closure๊ฐ ๋์ํ๋ ๋ฐฉ์์ ์ค๋ช ํ๋ ค๋ฉด ์ค์ฝํ(Scope)๋ผ๋ ๊ฐ๋ ๋ถํฐ ์ง๊ณ ๋์ด๊ฐ์ผ ํ๋ค.
- ์ค์ฝํ๋ ์คํ ์ปจํ ์คํธ๋ผ๊ณ ๋ ํ๋ฉฐ, ์ด๋ก ์ ์ผ๋ก๋ ์คํ ๊ฐ๋ฅํ ์ฝ๋๊ฐ ์คํ๋๋ ํ๊ฒฝ(?)์ด๋ผ๋ ์๋ฏธ๋ฅผ ๊ฐ๊ณ ์์(ํ์๋ ๋์ถฉ ๋ณ์๊ฐ ์ด๊ณ ์๋ ๊ตฌ์ญ ์ ๋๋ก ์ดํดํจ)
- JS๋ ์ง๊ธ๊น์ง var๋ฅผ ํตํ ํจ์ ์ค์ฝํ๋ฅผ ๋ฐ๋ผ์๊ณ , ES6+๋ถํฐ ์ถ๊ฐ๋ const์ let์ ์ด์ฉํด ๋ธ๋ก ์ค์ฝํ๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋์์
console.log("์ ์ญ ์ปจํ
์คํธ์
๋๋ค.");
function func1(){
console.log("func1 ์
๋๋ค.");
}
function func2(){
func1();
console.log("func2 ์
๋๋ค.");
}
func2();
ํจ์ ์ ์ธ ์์
๋ค์ ์๋ฅผ ์ฐธ๊ณ ํ์๋ฉด, ์ค์ฝํ๋ ๊ทธ ๋ณ์๊ฐ ํธ์ถ๋๋ ์์ ์ด ์๋๋ผ, ์ ์ธ๋๋ ์์ ์ ๊ณ ๋ คํ๋ค๋ ์ ์ ์ ์ ์๋ค.
var name = 'zero';
function log() {
console.log(name); // 2) ์ ์ญ ๋ณ์ name์ ์ฐธ์กฐ
}
function wrapper() {
name = 'nero'; // 1) ์ ์ญ๋ณ์ name ๊ฐ ๋ณ๊ฒฝ
log();
}
wrapper(); // ๊ฒฐ๊ณผ : nero ์ถ๋ ฅ
var name = 'zero';
function log() {
console.log(name); // 2) ์ ์ญ ๋ณ์ name์ ์ฐธ์กฐ
}
function wrapper() {
var name = 'nero'; // 1) name ์ ์ธ์ ๋ฐ๋ฅธ ์๋ก์ด ์ค์ฝํ ์์ฑ(์ง์ญ ๋ณ์ name)
log();
}
wrapper(); // ๊ฒฐ๊ณผ : zero ์ถ๋ ฅ
๊ทธ๋์ Closure๊ฐ ์ ์๊ธฐ๋ ๊ฑด๋ฐ?
๊ฒฐ๋ก ๋ถํฐ ์คํฌํ์๋ฉด, JS์ ๊ฐ๋น์ง ์ปฌ๋ ์ (Garbage Collection) ์ ์ฑ ๋๋ฌธ์ด๋ค.
Garbage Collection in JS
: ๋ถ๋ช C์ธ์ด์ ๊ฐ์ ์ ์์ค์ ์ธ์ด์์๋ malloc()๊ณผ free()๋ฅผ ํตํด ๊ฐ๋ฐ์๊ฐ ์ง์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ํด์ค์ผ ํ๋ค.
๊ทธ๋ฌ๋ ๊ณ ์์ค ์ธ์ด์ธ JS์์๋ ๋ฉ๋ชจ๋ฆฌ ํ ๋น์ด ๋ฐ์ํ๋ฉด ๊ทธ๊ฒ์ ์ถ์ ํ๊ณ , ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก์ด ๋ ์ด์ ํ์ํ์ง ์๊ฒ ๋์๋ ์ง๋ฅผ ์ค์ค๋ก ํ๋จํ์ฌ ํ์ํ๋ค.
์ธ๋ป ๋ณด๊ธฐ์๋ ํธ๋ฆฌํ ๊ธฐ๋ฅ์ด์ง๋ง, ๋ชจ๋ ๋ฌธ์ ๋ ์ค์ค๋ก ํ๋จํ์ฌ ํ์ํ๋ค๋ ์ ์์ ์์ํ๋ค. ์ธ์ ๋ฌด์์ด ์คํ๋๊ณ ์ฐธ์กฐ๋ ์ง ๋ชจ๋ฅด๋๋ฐ ์ด ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๋ ์ด์ ํ์ํ์ง ์๋ค๋ผ๊ณ ํ๋จํ๋ ๊ธฐ์ค์ ์ ๋์ ์ผ๋ก ์ ํ๊ธฐ๋ ํ๋ค๊ธฐ ๋๋ฌธ์ด๋ค.
JS๋ ๊ทธ ๊ธฐ์ค์ ์ต์์ ๊ฐ์ฒด๋ก๋ถํฐ์ ๋๋ฌ ๊ฐ๋ฅ์ฑ์ด๋ผ๋ ๊ฐ๋ ์ผ๋ก ์ ํ๊ณ , ๋๋ฌ์ด ๊ฐ๋ฅํ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ์์ ์ญ์
ํ์ง ์๊ฒ ํ๋ค.
* ์ฌ๊ธฐ์ ์ต์์ ๊ฐ์ฒด๋ ๋ธ๋ผ์ฐ์ ์์ window, Node.js์์ global์ด๋ค.
* ๋๋ฌ ๊ฐ๋ฅ์ฑ์ ์ฐธ์กฐ ๊ฐ๋ฅ์ฑ / ํธ์ถ ๊ฐ๋ฅ์ฑ ๋ฑ์ผ๋ก ์๊ฐํด๋ ๋ ๊ฒ ๊ฐ๋ค.
์์ ๋ดค๋ ์ฝ๋๋ฅผ ๋ค์ ๋ณด์๋ฉด,
function makeFunc() {
const name = 'Think Thing';
function displayName() { // Closure ํ์ฑ
alert(name);
}
return displayName;
}
const myFunc = makeFunc(); // myFunc๋ณ์์ displayName์ ๋ฆฌํด
myFunc();
- ์ด ์ฝ๋๋ฅผ ์คํ ์์๋๋ก ๋์ดํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
- ์ต์์ ๊ฐ์ฒด์ ๋ณ์(์ ์ญ ๋ณ์)์ธ myFunc๊ฐ makeFunc๋ฅผ ์ฐธ์กฐ
- makeFunc๋ displayName์ ๋ฐํํ๋๋ฐ, ์ด๋ makeFunc ๋ด๋ถ์ name์ ์ฐธ์กฐ
- ์ต์ข ์ ์ผ๋ก ํ์ฑ๋ ์ฐ๊ฒฐ ๊ณ ๋ฆฌ์ ๋ฐ๋ผ ์ต์์ ๊ฐ์ฒด๋ก๋ถํฐ name์ ๋๋ฌ ๊ฐ๋ฅ์ฑ์ด ์๊น ⇒ ํด๋น ๋ฉ๋ชจ๋ฆฌ๋ ๊ฐ๋น์ง ์ปฌ๋ ํฐ๊ฐ ํ์ํ์ง ์์
- ๊ทธ๋ฌ๋ฏ๋ก Closure๊ฐ ๋ฐ์
๊ทธ๋์ ์ด๊ฑฐ ์ ์ด๋ค๊ณ โ
Closure๋ฅผ ์ฌ์ฉํด ์ป์ ์ ์๋ ์ฅ๋จ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
๐โ๏ธ ์ฅ์
- ํจ์๊ฐ ์ ์๋ ์ค์ฝํ ์ด์ธ์ ๊ณณ์์ ์ฌ์ฉ๋ ๋ ๋ณ์๋ฅผ ๋ ธ์ถ์ํค์ง ์์ private์ฒ๋ผ ์ฌ์ฉํด ์ธ๋ถ์ ์ ๊ทผ์ ์ฐจ๋จํ ์ ์์
- ์ด๋ Class์์ Field๋ฅผ private์ผ๋ก ์ ์ธํ ํ get set์ผ๋ก ์ ๊ทผํ๋ ๊ฒ๊ณผ ๊ฐ์ ํจ๊ณผ
๐ โ๏ธ ๋จ์
- ์์นซํ๋ฉด ๊ฐ๋น์ง ์ปฌ๋ ์ ์ผ๋ก ์ง์์ง์ง ์๋ ๋ณ์๊ฐ ๋ง์์ ธ ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น๋ก ์ด์ด์ง ์ ์์
- ์ค์ฝํ ์ฒด์ธ์ ๊ฑฐ์ฌ๋ฌ ์ฌ๋ผ๊ฐ๋ฉด์ ๋ณ์๋ฅผ ์ฐพ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ด ๋จ์ด์ง
TMI ๐โ๏ธ๐โ๏ธ
React์ useState๋ Closure๋ฅผ ํ์ฉํด ๊ตฌํํ ์ ์๋ค!
function useState(initialValue) {
var _val = initialValue // _val์ useState์ ์ํด ๋ง๋ค์ด์ง ์ง์ญ ๋ณ์
function state() {
// state๋ ๋ด๋ถ ํจ์์ด์ Closure
return _val // state()๋ ๋ถ๋ชจ ํจ์์ ์ ์๋ _val์ ์ฐธ์กฐ
}
function setState(newVal) {
// ๋ง์ฐฌ๊ฐ์ง
_val = newVal // _val๋ฅผ ๋
ธ์ถํ์ง ์๊ณ _val๋ฅผ ๋ณ๊ฒฝ
}
return [state, setState] // ์ธ๋ถ์์ ์ฌ์ฉํ๊ธฐ ์ํด ํจ์๋ค์ ๋
ธ์ถ
}
์ฐธ๊ณ ์๋ฃ
- https://ko.javascript.info/garbage-collection
- https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management
- https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures
- https://www.netlify.com/blog/2019/03/11/deep-dive-how-do-react-hooks-really-work/
- https://chanhuiseok.github.io/posts/js-4/