๐ 02. ํด๋ก์ โ ํจ์๊ฐ ์ฃฝ์ด๋ ๊ธฐ์ตํ๋ ๋ณ์์ ๋น๋ฐ
๐ ๊ฐ์
ํจ์๊ฐ ํ์ด๋ ์ค์ฝํ๋ฅผ ๊ธฐ์ตํ๋ ํด๋ก์ ์ ๋ณธ์ง, ์ค๋ฌด ํจํด(๋ฐ์ดํฐ ์๋, ํฉํ ๋ฆฌ ํจ์, ๋ฉ๋ชจ์ด์ ์ด์ )์ ์์ ์ ๋ณตํฉ๋๋ค.
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- ํด๋ก์ ๊ฐ ๋จ์ํ "ํจ์ ์์ ํจ์"๊ฐ ์๋๋ผ ์ค์ฝํ ์บก์ฒ ๋ฉ์ปค๋์ฆ์์ ์ค๋ช ํ ์ ์๋ค.
- ๋ฐ์ดํฐ ์๋, ํฉํ ๋ฆฌ ํจ์, ๋ฉ๋ชจ์ด์ ์ด์ ๋ฑ ์ค๋ฌด ํด๋ก์ ํจํด์ ์์ฑํ ์ ์๋ค.
- ํด๋ก์ ๋ก ์ธํ ๋ฉ๋ชจ๋ฆฌ ๋์ ํจํด์ ์ธ์ํ๊ณ ์๋ฐฉํ ์ ์๋ค.
๐ ๋ชฉ์ฐจ
- ๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
- ๐ค 1. ์ ์์์ผ ํ๋๊ฐ?
- ๐ฌ 2. ํด๋ก์ ์ ๋ณธ์ง
- ๐๏ธ 3. ์ค๋ฌด ํด๋ก์ ํจํด
- โ ๏ธ 4. ํด๋ก์ ํจ์ ๊ณผ ๋ฉ๋ชจ๋ฆฌ ๋์
- ๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
- ๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
- ๐ ๋ ์์๋ณด๊ธฐ
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 22๋ถ(์ ์ฒด) / ํต์ฌ ํํธ๋ง: 13๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ํ๋ฆ
[ํด๋ก์ ์ ์ ์] โ [๋ ์์ปฌ ํ๊ฒฝ ์ดํด] โ [4๊ฐ์ง ์ค๋ฌด ํจํด] โ [๋ฉ๋ชจ๋ฆฌ ๋์ ์ฃผ์์ฌํญ]
๐ฏ ์ด ๋ฌธ์๋ฅผ ๋ค ์ฝ์ผ๋ฉด ํ ์ ์๋ ๊ฒ
- "ํด๋ก์ ๊ฐ ๋ญ๊ฐ์?" ๋ฉด์ ์ง๋ฌธ์ ์ฝ๋์ ํจ๊ป ๋ตํ ์ ์๋ค.
- ๋ชจ๋ ํจํด์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์บก์ํํ ์ ์๋ค.
- React์
useState,useCallback์ด ํด๋ก์ ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋์ํจ์ ์ค๋ช ํ ์ ์๋ค.
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
๐ฃ ์์ฒ : "์ํธ ๋, ์ค๋ ๊ฒ์๊ธ ์กฐํ์ ์นด์ดํฐ๋ฅผ ๋ง๋ค๋ค๊ฐ ์ด์ํ ๊ฑธ ๋ฐ๊ฒฌํ์ด์. ์ ์ญ ๋ณ์๋ก
viewCount๋ฅผ ์ ์ธํ๋๋... ๋ค๋ฅธ ํ์ผ์์ ๋๊ฐ ๋งviewCount = 0์ผ๋ก ์ด๊ธฐํํด๋ฒ๋ ธ์ด์. ์ ์ญ ๋ณ์๋ ์ฐ์ง ๋ง๋ผ๋ ๊ฑด ์๊ฒ ๋๋ฐ, ๊ทธ๋ผ ์นด์ดํฐ ๊ฐ์ ์ด๋์ ์ด๋ป๊ฒ ๋ณด๊ดํด์ผ ํด์? ํด๋์ค ์จ์ผ ํ๋์?"
๐ฆ ์ํธ: "ํด๋์ค๋ณด๋ค ๋ ๊ฐ๋ณ๊ณ ์ฐ์ํ ๋ฐฉ๋ฒ์ด ์์ด. ํด๋ก์ ๋ฅผ ์ฐ๋ฉด ๋ผ. ํจ์ ์์ ๋ณ์๋ฅผ ์ ์ธํ๊ณ , ๊ทธ ๋ณ์๋ฅผ ์กฐ์ํ๋ ํจ์๋ง ๋ด๋ณด๋ด๋ฉด โ ์ธ๋ถ์์ ์ง์ ์ ๊ทผํ๋ ๊ฑด ๋ถ๊ฐ๋ฅํ๋ฉด์ ์ํ๋ ๊ณ์ ์ ์ง๋ผ. ์ค๋ ํด๋ก์ ํ๋ ์ ๋๋ก ๋ฐฐ์๋๋ฉด, React
useState๊ฐ ์ ์ ๋ ๊ฒ ์๊ฒผ๋์ง๋ ์๋์ผ๋ก ์ดํด๋ผ."
๐ค 1. ์ ์์์ผ ํ๋๊ฐ?
์ํธ ๋ฆฌ๋ ๋์ด ์์ฒ ์ด์๊ฒ ์ฒ์ ํด๋ก์ ๋ฅผ ์ค๋ช
ํ์ ๋ ๋ฑ ํ๋ง๋๋ก ์์ฝํ๋ค: "ํด๋ก์ ๊ฐ ๋ญ์ง ๋ชจ๋ฅด๋ฉด React useState๊ฐ ์ ์ ๋ ๊ฒ ์๊ฒผ๋์ง ํ์ ์ดํด ๋ชป ํด." ํด๋ก์ ๋ JS์ ๊ฐ์ฅ ๊ฐ๋ ฅํ๋ฉด์ ๊ฐ์ฅ ์คํด๋ฐ๋ ๊ฐ๋
์ด๋ค. ๋ฉด์ ์์ ๋จ๊ณจ๋ก ๋ฑ์ฅํ๋ ์ด์ ๊ฐ ์๋ค โ ํด๋ก์ ๋ฅผ ์ดํดํ๋ฉด ๋ค์ ๋ชจ๋ ๊ฒ์ด ์ค๋ช
๋๋ค:
- React
useState์ ์ํ๊ฐ ๋ฆฌ๋ ๋๋ง ํ์๋ ์ ์ง๋๋ ์ด์ setTimeout์ฝ๋ฐฑ์ด ์ธ๋ถ ๋ณ์๋ฅผ "๊ธฐ์ต"ํ๋ ์ด์- ๋ชจ๋ ํจํด์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์บก์ํํ๋ ๋ฐฉ๋ฒ
useCallback,useMemo๊ฐ ์์กด์ฑ ๋ฐฐ์ด์ ํ์๋ก ํ๋ ์ด์
MDN ๊ณต์ ์ ์: "A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment)." โ ํด๋ก์ ๋ ํจ์์ ๊ทธ ํจ์๊ฐ ์ ์ธ๋์ ๋์ ๋ ์์ปฌ ํ๊ฒฝ์ ์กฐํฉ์ด๋ค.
๐ฌ 2. ํด๋ก์ ์ ๋ณธ์ง
๋ ์์ปฌ ํ๊ฒฝ๊ณผ ํด๋ก์
์๋ฐ์คํฌ๋ฆฝํธ์ ๋ชจ๋ ํจ์๋ ํ์ด๋ ๋ ์์ ์ด ์ ์๋ ๋ (๋ ์์ปฌ ํ๊ฒฝ)์ ๋ํ ๊ธฐ์ต์ ํ๊ณ ๋์ต๋๋ค. ์์ฒ ์ด๊ฐ ๊ณ ๋ฏผํ๋ ์นด์ดํฐ ๋ณ์ ์ค์ผ ๋ฌธ์ ๋ฅผ ์ด ๊ธฐ์ต์ ํ์ฉํด ์ด๋ป๊ฒ ํด๊ฒฐํ๋์ง ๋ณด๊ฒ ์ต๋๋ค.
// ๐ฃ ์์ฒ : "์ ์ญ ๋ณ์ ๋์ ์ด๋ ๊ฒ ์ง๋ฉด ๋๋ ๊ฑด๊ฐ์?" โ ์์๋ค ์ปค๋ฎค๋ํฐ ๊ฒ์๊ธ ์กฐํ์ ์นด์ดํฐ
function createViewCounter() {
let count = 0; // โ ์ด ๋ณ์๊ฐ ํด๋ก์ ์ "์บก์ฒ"๋๋ค
function increment() {
count++;
console.log(`์กฐํ์: ${count}`);
}
function getCount() {
return count;
}
return { increment, getCount };
}
const postCounter = createViewCounter();
postCounter.increment(); // ์กฐํ์: 1
postCounter.increment(); // ์กฐํ์: 2
postCounter.increment(); // ์กฐํ์: 3
console.log(postCounter.getCount()); // 3
// ์ธ๋ถ์์ count์ ์ง์ ์ ๊ทผ ๋ถ๊ฐ!
console.log(postCounter.count); // undefined โ ์๋ฒฝํ ์๋ํต์ฌ: createViewCounter()๊ฐ ์ด๋ฏธ ๋ฐํ(์ข
๋ฃ) ๋์์๋ count๋ ์ฌ๋ผ์ง์ง ์๋๋ค. increment์ getCount๊ฐ count๋ฅผ ์ฐธ์กฐํ๋ ํ, JS ๊ฐ๋น์ง ์ปฌ๋ ํฐ๋ ๊ทธ ๋ ์์ปฌ ํ๊ฒฝ์ ์๊ฑฐํ์ง ์๋๋ค.
ํด๋ก์ ๊ฐ ์์ฑ๋๋ ์๊ฐ
ํจ์๊ฐ ์ด๋ฏธ ์คํ์ ๋ง์น๊ณ ์ฌ๋ผ์ก๋๋ฐ๋, ๊ทธ ์์ ์์คํ ์ ๋ณด๊ฐ ๊ณ์ ์ ์ง๋๋ ๋ง๋ฒ ๊ฐ์ ์๊ฐ์ ์ฝ๋๋ก ์๊ฐํํด ๋ณด๊ฒ ์ต๋๋ค.
function outer() {
const message = "์๋
!"; // outer์ ๋ ์์ปฌ ํ๊ฒฝ
function inner() {
// inner ํจ์๋ ์์ฑ๋ ๋ outer์ ๋ ์์ปฌ ํ๊ฒฝ์ [[Environment]]์ ์ ์ฅ
console.log(message); // ํด๋ก์ ๋ฅผ ํตํด ์ ๊ทผ
}
return inner; // inner ํจ์ ์์ฒด๋ฅผ ๋ฐํ
}
const closureFunc = outer(); // outer ์คํ ์ข
๋ฃ โ ์ผ๋ฐ์ ์ผ๋ก message๋ ์ฌ๋ผ์ ธ์ผ ํจ
closureFunc(); // "์๋
!" โ ํ์ง๋ง closureFunc์ด outer์ ํ๊ฒฝ์ ๋ค๊ณ ์์ด์ ์ด์์์
// ๋ฉ๋ชจ๋ฆฌ ๊ด์ :
// outer()๊ฐ ์ข
๋ฃ๋์ง๋ง, closureFunc([[Environment]])๊ฐ outer์ ๋ ์์ปฌ ํ๊ฒฝ์ ์ฐธ์กฐ ์ค
// โ GC(๊ฐ๋น์ง ์ปฌ๋ ํฐ)๊ฐ ์๊ฑฐ ๋ถ๊ฐ โ message๋ ๋ฉ๋ชจ๋ฆฌ์ ์ด์์์๐๏ธ 3. ์ค๋ฌด ํด๋ก์ ํจํด
๋ฐ์ดํฐ ์๋ (Private State)
์ธ๋ถ์์ ๋ณ์๋ฅผ ๋ง์๋๋ก ์ฃผ๋ฌด๋ฅด์ง ๋ชปํ๊ฒ ๊ฝ๊ฝ ์จ๊ธฐ๊ณ ์ถ์ ๋ ํด๋ก์ ๊ฐ ํ์ฝํฉ๋๋ค. ์์ฒ ์ด๊ฐ ์ฒ์ ์ง ์ฝ๋์, ์ํธ ๋ฆฌ๋์ ์๊ธธ์ด ๋ฟ์ ์ฝ๋๋ฅผ ๋น๊ตํด ๋ณด์ธ์.
// โ ์์งํ ์ฝ๋ (Naive Approach) โ ์ ์ญ ๋
ธ์ถ
// ๐ฃ ์์ฒ ์ ์ด๊ธฐ ์ฝ๋
let postLikeCount = 0;
function like() {
postLikeCount++;
}
function unlike() {
postLikeCount--;
}
// ๋ฌธ์ : ๋๊ตฌ๋ postLikeCount = 9999 ๋ก ์กฐ์ ๊ฐ๋ฅ
// โ
ํด๋ก์ ๋ก ๋ฐ์ดํฐ ์๋ (Pro Approach)
// ๐ฆ ์ํธ์ ๋ฆฌํฉํ ๋ง
function createLikeManager(initialCount = 0) {
let _count = initialCount; // ์ธ๋ถ ์ ๊ทผ ๋ถ๊ฐํ private ๋ณ์
return {
like() {
if (_count >= 9999) return; // ๋น์ฆ๋์ค ๋ก์ง๋ ๋ด๋ถ์์ ์ฒ๋ฆฌ
_count++;
},
unlike() {
if (_count <= 0) return;
_count--;
},
getCount() {
return _count;
},
};
}
const likeManager = createLikeManager(42);
likeManager.like();
likeManager.like();
console.log(likeManager.getCount()); // 44
// likeManager._count ๋ undefined โ ์์ ๋ด์ธํฉํ ๋ฆฌ ํจ์ (Factory Function)
์์ PM์ด "๊ฒ์๊ธ๋ง๋ค ๋ ๋ฆฝ์ ์ผ๋ก ์นด์ดํธ๊ฐ ๋์๊ฐ์ผ ํด์"๋ผ๋ ๋ฏธ์ ์ ์คฌ์ ๋, ์ํธ ๋ฆฌ๋ ๋์ด ๊ถ์ฅํ ๋ฐฉ์์ ๋๋ค. ํ๋์ ์ค๊ณ๋๋ก ์ฌ๋ฌ ๊ฐ์ ๋ ๋ฆฝ์ ์ธ ๊ฒฐ๊ณผ๋ฌผ์ ์ฐ์ด๋ผ ์ ์์ต๋๋ค.
// ์์๋ค ์ปค๋ฎค๋ํฐ โ ๊ฒ์๊ธ๋ณ ๋
๋ฆฝ์ ์ธ ์ํ ๊ด๋ฆฌ
function createPostManager(postId) {
let viewCount = 0;
let likeCount = 0;
const comments = [];
return {
view() {
viewCount++;
return viewCount;
},
like() {
likeCount++;
return likeCount;
},
addComment(text) {
const comment = { id: comments.length + 1, text, postId };
comments.push(comment);
return comment;
},
getSummary() {
return { postId, viewCount, likeCount, commentCount: comments.length };
},
};
}
// ๊ฐ ๊ฒ์๊ธ๋ง๋ค ๋
๋ฆฝ์ ์ธ ์ํ
const post1 = createPostManager(1);
const post2 = createPostManager(2);
post1.view();
post1.view();
post1.like();
post2.view();
console.log(post1.getSummary()); // { postId: 1, viewCount: 2, likeCount: 1, commentCount: 0 }
console.log(post2.getSummary()); // { postId: 2, viewCount: 1, likeCount: 0, commentCount: 0 }
// post1๊ณผ post2๋ ์๋ก์ ์ํ์ ์ ํ ์ํฅ์ ์ฃผ์ง ์์ โ
๋ฉ๋ชจ์ด์ ์ด์ (Memoization)
์์ ๋์์ด๋๊ฐ "๊ฒ์ํ ๋๋ง๋ค ๋ฌํ๊ฒ ํ๋ฉด์ด ๋ฆ๊ฒ ๋ ์"๋ผ๊ณ ์ ๋ณดํ ์ํฉ์ ๋๋ค. ์ํธ ๋ฆฌ๋ ๋์ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๊ตณ์ด ๋ ๋ฒ ๊ณ์ฐํ์ง ์๋๋ก, ํด๋ก์ ์ '๊ธฐ์ต๋ ฅ'์ ํ์ฉํ ์บ์ฑ ์ฅ์น๋ฅผ ๋์ ํ์ต๋๋ค.
// ์์๋ค ์ปค๋ฎค๋ํฐ โ ๊ฒ์ ํํฐ ๊ฒฐ๊ณผ ์บ์ฑ
function memoize(fn) {
const cache = new Map(); // ํด๋ก์ ๋ก ์บก์ฒ๋ ์บ์
return function (...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log("์บ์ ํํธ! ๐ฏ");
return cache.get(key);
}
const result = fn(...args);
cache.set(key, result);
return result;
};
}
// ๋ฌด๊ฑฐ์ด ํํฐ๋ง ํจ์ (์ค์ ๋ก๋ ๋ณต์กํ ์ฐ์ฐ)
const heavyFilter = (posts, keyword) => {
console.log(`DB ์กฐํ ์ค... keyword: ${keyword}`);
return posts.filter((p) => p.title.includes(keyword));
};
const cachedFilter = memoize(heavyFilter);
const posts = [
{ id: 1, title: "ํด๋ก์ ์์ ์ ๋ณต" },
{ id: 2, title: "React ํ
์ ๋ณต" },
{ id: 3, title: "ํด๋ก์ ์ฌํ" },
];
cachedFilter(posts, "ํด๋ก์ "); // DB ์กฐํ ์ค...
cachedFilter(posts, "ํด๋ก์ "); // ์บ์ ํํธ! ๐ฏ โ ์ฌ๊ณ์ฐ ์์
cachedFilter(posts, "React"); // DB ์กฐํ ์ค...๋ถ๋ถ ์ ์ฉ ํจ์ (Partial Application)
๊ณตํต์ผ๋ก ๋ค์ด๊ฐ๋ ์ค์ ์ ๋ฏธ๋ฆฌ ๋ฑ ๊ณ ์ ํด๋๊ณ , ๋์ค์ ์๋งน์ด๋ง ์ ๋ฐ๊ฟ์ ์ธ ์ ์๋ ํธ๋ฆฌํ ๋๊ตฌ๋ฅผ ๋ง๋ค ๋๋ ํด๋ก์ ๊ฐ ์ฐ์ ๋๋ค.
// ์์๋ค ์ปค๋ฎค๋ํฐ โ API ํธ์ถ ํฌํผ
function createApiCaller(baseURL) {
return function (endpoint, options = {}) {
return fetch(`${baseURL}${endpoint}`, {
headers: {
"Content-Type": "application/json",
...options.headers,
},
...options,
});
};
}
// baseURL์ ํ ๋ฒ๋ง ์ค์ ํ๊ณ ์ฌ๋ฌ API ํธ์ถ์ ์ฌ์ฌ์ฉ
const devApi = createApiCaller("https://dev-api.youngsu.com");
const prodApi = createApiCaller("https://api.youngsu.com");
// ์ค์ ์ฌ์ฉ โ ๊ฐ๊ฒฐํ๊ฒ!
devApi("/posts"); // https://dev-api.youngsu.com/posts
devApi("/users/42"); // https://dev-api.youngsu.com/users/42
prodApi("/posts"); // https://api.youngsu.com/postsโ ๏ธ 4. ํด๋ก์ ํจ์ ๊ณผ ๋ฉ๋ชจ๋ฆฌ ๋์
ํด๋ก์ ์ '๊ธฐ์ต๋ ฅ'์ด ๋๋ฌด ์ข์ผ๋ฉด ๋ฌธ์ ๊ฐ ๋ฉ๋๋ค. ์ด๋ฏธ ์์ด์ผ ํ ๊ฑฐ๋ํ ๋ฐ์ดํฐ๊น์ง ํ์ ๋ถ๋ค๊ณ ์์ผ๋ฉด ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ถ์กฑํด์ง๊ฑฐ๋ ์. ์ํธ ๋ฆฌ๋ ๋์ด ์์ฒ ์ด์ ์ฝ๋์์ ๋ฐ๊ฒฌํ ์ํํ ํจํด์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
// โ ๋ฉ๋ชจ๋ฆฌ ๋์ ํจํด
// ๐ฃ ์์ฒ ์ ์ฝ๋ โ ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์์์ ๊ฑฐ๋ํ ๋ฐ์ดํฐ๋ฅผ ํด๋ก์ ๋ก ์บก์ฒ
function setupUI() {
const hugeUserList = fetchAllUsers(); // ์๋ง ๋ช
์ ์ ์ ๋ฐ์ดํฐ (์ MB)
document.getElementById("search-btn").addEventListener("click", function () {
// hugeUserList ์ ์ฒด๋ฅผ ํด๋ก์ ๋ก ์ฐธ์กฐ
const result = hugeUserList.filter(/* ... */);
renderResult(result);
});
// setupUI๊ฐ ๋๋ ํ์๋:
// - click ์ด๋ฒคํธ ๋ฆฌ์ค๋๊ฐ ์ด์์๊ณ
// - ๊ทธ ๋ฆฌ์ค๋๊ฐ hugeUserList๋ฅผ ์ฐธ์กฐํ๋ฏ๋ก
// - hugeUserList๋ GC ์๊ฑฐ ๋ถ๊ฐ โ ๋ฉ๋ชจ๋ฆฌ ๋์
}
// โ
ํด๊ฒฐ์ฑ
โ ํ์ํ ๋ฐ์ดํฐ๋ง ํด๋ก์ ์ ๊ฐ๋ฌ๋ผ
function setupUI() {
const hugeUserList = fetchAllUsers();
const processedList = preprocessForSearch(hugeUserList); // ๊ฒฝ๋ํ๋ ๋ฐ์ดํฐ๋ง ์ถ์ถ
hugeUserList = null; // ์๋ณธ ์ฐธ์กฐ ํด์ โ GC ๊ฐ๋ฅ
document.getElementById("search-btn").addEventListener("click", function () {
const result = processedList.filter(/* ... */); // ๊ฒฝ๋ ๋ฐ์ดํฐ๋ง ์ฐธ์กฐ
renderResult(result);
});
}ํด๋ก์ ํจ์ ์ฒดํฌ๋ฆฌ์คํธ:
- ๊ฑฐ๋ํ ๋ฐ์ดํฐ๋ฅผ ํด๋ก์ ๋ก ์บก์ฒํ๊ณ ์์ง๋ ์์๊ฐ?
- ์ด๋ฒคํธ ๋ฆฌ์ค๋๊ฐ ํด์ (removeEventListener)๋์ง ์๊ณ ๊ณ์ ์ด์์์ง๋ ์์๊ฐ?
-
setInterval์ฝ๋ฐฑ ์์์ ํด๋ก์ ๋ก ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๊ณ ์์ง๋ ์์๊ฐ? - ์ปดํฌ๋ํธ๊ฐ ์ธ๋ง์ดํธ๋๋๋ฐ ํด๋ก์ ๊ฐ ๊ทธ ์ํ๋ฅผ ์์ง ์ฐธ์กฐํ๊ณ ์์ง๋ ์์๊ฐ?
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. ์๋ ์ฝ๋์ ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ์์ธกํ๊ณ ์ด์ ๋ฅผ ์ค๋ช ํ๋ผ.
function makeAdder(x) {
return function (y) {
return x + y;
};
}
const add5 = makeAdder(5);
const add10 = makeAdder(10);
console.log(add5(3)); // ?
console.log(add10(3)); // ?
console.log(add5(10)); // ?โ
์ ๋ต: 8, 13, 15
๐ก ์์ธ ํด์ค:
makeAdder(5)ํธ์ถ ์, ๋ด๋ถ ํจ์(ํด๋ก์ )๊ฐx = 5์ธ ๋ ์์ปฌ ํ๊ฒฝ์ ์บก์ฒํ์ฌadd5์ ๋ฐํ๋๋ค.makeAdder(10)ํธ์ถ ์, ๋ ๋ฆฝ์ ์ธ ๋ค๋ฅธ ๋ ์์ปฌ ํ๊ฒฝ ์์x = 10์ ์บก์ฒํ ํด๋ก์ ๊ฐadd10์ ์ ์ฅ๋๋ค.add5์add10์ ๊ฐ์์x๋ฅผ ๋ณ๋๋ก ๊ธฐ์ต ํ๋ฏ๋ก ์๋ก์๊ฒ ์ํฅ์ ์ฃผ์ง ์๋๋ค.- ๐ ํต์ฌ ๊ธฐ์ต๋ฒ: "ํฉํ ๋ฆฌ ํจ์๋ฅผ ํ ๋ฒ ํธ์ถํ ๋๋ง๋ค ์๋ก์ด ๋ ์์ปฌ ํ๊ฒฝ ์ด ์์ฑ๋๊ณ , ๋ฐํ๋ ํด๋ก์ ๋ ๊ทธ ํ๊ฒฝ์ ๋ ์ ํ๋ค."
Q2. ํด๋ก์ ์ React useState์ ๊ด๊ณ๋ฅผ ์ค๋ช
ํ๋ผ.
โ
์ ๋ต: useState๋ ํด๋ก์ ๋ฅผ ์ฌ์ฉํด ์ํ(state)๋ฅผ ์ปดํฌ๋ํธ ํจ์์ ์ธ๋ถ์์ ๋ณด๊ดํ๊ณ , setter ํจ์๋ฅผ ํตํด์๋ง ์ ๊ทผํ๊ฒ ํ๋ค.
๐ก ์์ธ ํด์ค:
- React์
useState๋ฅผ ๊ทน๋๋ก ๋จ์ํํ๋ฉด ์๋์ ๊ฐ๋ค:function useState(initialValue) { let _state = initialValue; // React ๋ด๋ถ์ ๋ณด๊ด (ํด๋ก์ ๋ก ์บก์ฒ) function setState(newValue) { _state = newValue; rerender(); // ๋ฆฌ๋ ๋ ํธ๋ฆฌ๊ฑฐ } return [_state, setState]; // ํ์ฌ ๊ฐ๊ณผ setter๋ง ๋ ธ์ถ } - ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ ๋๋ง๋ค
useState๊ฐ ๋ค์ ํธ์ถ๋์ง๋ง, React๋ ๋ด๋ถ์ ์ผ๋ก ๋์ผํ_state๊ฐ์ ์ ์งํ๋ค. ์ด๊ฒ์ด ํด๋ก์ (๋ ์์ปฌ ํ๊ฒฝ ์บก์ฒ) ๋๋ถ์ ๊ฐ๋ฅํ๋ค. - ๐ ํต์ฌ ๊ธฐ์ต๋ฒ: "React์ ์ํ๋ ์ปดํฌ๋ํธ ํจ์ ๋ฐ์์ ํด๋ก์ ๋ก ๋ณด๊ด ๋๊ณ ,
setState๋ผ๋ ์ฐฝ๊ตฌ๋ฅผ ํตํด์๋ง ๋ณ๊ฒฝ๋๋ค."
Q3. ์์ฒ ์ด์ ํ ์คํธ ํ์ โ ์๋์ด ๋ฉด์ ๋์
์์ฒ ์ด๊ฐ ์ด์ง์ ์ํด ์คํํธ์ ๋ฉด์ ์ ๋ณด๋ฌ ๊ฐ๋ค. ๋ฉด์ ๊ด์ด ๋ฌป๋๋ค.
"ํด๋ก์ ๋ก ์ธํ ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ๋ ์ํฉ๊ณผ, ๊ทธ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ค๋ช ํด์ฃผ์ธ์."
โ ์ ๋ต: ํด๋ก์ ๊ฐ ๋ถํ์ํ๊ฒ ์ค๋ ์ด์์๋ ๋์ฉ๋ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐ ํ ๋ ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ๋ค. ํด๊ฒฐ์ฑ ์ ์ฐธ์กฐ๋ฅผ ๋ช ์์ ์ผ๋ก ๋๊ฑฐ๋(null ํ ๋น), ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ํด์ ํ๊ฑฐ๋, ํ์ํ ๋ฐ์ดํฐ๋ง ์ถ์ถํด ๊ฒฝ๋ํํ๋ ๊ฒ์ด๋ค.
๐ก ์์ธ ํด์ค:
- ๋์ ๋ฐ์ ์กฐ๊ฑด: โ ํด๋ก์ (๋ด๋ถ ํจ์)๊ฐ ์ด์์๊ณ โก ๊ทธ ํด๋ก์ ๊ฐ ํฐ ๋ฐ์ดํฐ๋ฅผ ์ฐธ์กฐํ๋ฉฐ โข ๊ทธ ๋ฐ์ดํฐ๊ฐ ๋ ์ด์ ํ์ ์๋๋ฐ๋ GC๊ฐ ์๊ฑฐํ์ง ๋ชปํ๋ ์ํฉ.
- ์ค๋ฌด ์ฌ๋ก: ์ด๋ฒคํธ ๋ฆฌ์ค๋,
setInterval, ์ ์ญ ๋ณ์์ ์ ์ฅ๋ ํด๋ก์ ๋ฑ. - ํด๊ฒฐ ์ ๋ต:
- ๋ถํ์ํด์ง ์ด๋ฒคํธ ๋ฆฌ์ค๋๋
removeEventListener๋ก ์ ๊ฑฐ setInterval์clearInterval๋ก ํด์ - ํด๋ก์ ์ ํฌํจ๋ ๋ฐ์ดํฐ๋ ํ์ํ ๋ถ๋ถ๋ง ์ถ์ถํด ์บก์ฒ
- React์์๋
useEffectcleanup ํจ์๋ก ๋ฆฌ์ค๋ ์ ๋ฆฌ
- ๋ถํ์ํด์ง ์ด๋ฒคํธ ๋ฆฌ์ค๋๋
- ๐ ํต์ฌ ๊ธฐ์ต๋ฒ: "ํด๋ก์ ๊ฐ ๊ธฐ์ตํ๋ ๊ฑด ๊ฐ์ด ์๋๋ผ ์ฐธ์กฐ์ ๋๋ค. ์ฐธ์กฐ๊ฐ ๋์ด์ง์ง ์๋ ํ ๊ฐ๋น์ง ์ปฌ๋ ํฐ๋ ์ด์ฐํ ์ ์์ผ๋, ๋ถํ์ํด์ง ์ฐธ์กฐ๋ ์ ๊ทน์ ์ผ๋ก ๋์ด์ฃผ์ด์ผ ํฉ๋๋ค."
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
์ค๋ ์ ์ฌ์ ๋ญ ๋จน์๋์ง๋ ๊ธฐ์ต ์ ๋๋๋ฐ ํด๋ก์ ๋ ๋จธ๋ฆฟ์์ ์ ๋ช ํ๊ฒ ๋จ์์๋ค. ์ ๊ธฐํ๋ค. ์๋ง ์ํธ ๋์ด "ํจ์๊ฐ ํ์ด๋ ๊ณณ์ ๊ธฐ์ตํ๋ค"๋ ๋ง์ ๋ฑ ํ ๋ง๋๋ก ์ ๋ฆฌํด์ค์ ๊ทธ๋ฐ ๊ฒ ๊ฐ๋ค.
์ฌ์ค ๋๋ ๊ทธ๋์ ํด๋ก์ ๋ฅผ ์ฐ๋ฉด์๋ ํด๋ก์ ์ธ์ง ๋ชฐ๋๋ค. setTimeout ์์์ ์ธ๋ถ ๋ณ์ ์ฐ๋ ๊ฑฐ, ์ด๋ฒคํธ ํธ๋ค๋ฌ์์ ์นด์ดํฐ ๋ณ์ ์ ๊ทผํ๋ ๊ฑฐ โ ์ ๋ถ ํด๋ก์ ์๋ค. ๊ฐ๋
์ ์ด๋ฏธ ์์ ์ต์ด์์๋๋ฐ ์ด๋ฆ๋ง ๋ชฐ๋๋ ๊ฑฐ๋ค.
๐ก ์ค๋์ ๊ตํ: "ํด๋ก์ ๋ 'ํจ์ ์์ ํจ์'๊ฐ ์๋๋ผ, ํจ์๊ฐ ํ์ด๋ ํ๊ฒฝ์ ๋ค๊ณ ๋ค๋๋ ๊ฒ์ด๋ค. ๊ทธ ํ๊ฒฝ์ด ์ด์์๋ ํ, ๊ทธ ์์ ๋ณ์๋ ์ด์์๋ค."
๋ด์ผ์ this ๋ฐ์ธ๋ฉ ๊ณต๋ถํด์ผ ํ๋๋ฐ... ์์งํ ์กฐ๊ธ ๋ฌด์ญ๋ค. ์ํธ ๋์ด "this๋ ํ์ดํ ํจ์๋ ์ผ๋ฐ ํจ์๊ฐ ์์ ํ ๋ฌ๋ผ" ๋ผ๊ณ ๊ท๋ํด์คฌ๋๋ฐ, ๋ถ๋ช
๋ด ์์์ ๊นจ๋ถ์๋ ๋ด์ฉ์ด ๋์ฌ ๊ฒ ๊ฐ๋ค. ํฌ์ค์ฅ์์ ์ด๋ํ๋ฉด์ ๊ฐ์ค ์ข ๋ค์ง๊ณ ์์ผ๊ฒ ๋ค.