Closure
Closure бол JavaScript-ийн хамгийн хүчирхэг бөгөөд анх сонсоход хамгийн гайхмаар ойлголтуудын нэг. Олон шинэ программист closure-тай танилцаад "энэ юу вэ?" гэж толгой эргэдэг — тэгэхдээ аажмаар уншаарай, жишээнүүд бүгдийг тодруулна.
Энгийнээр тайлбарлавал: closure нь функц өөрийгөө үүсгэсэн орчны хувьсагчдыг тэр орчин устсаны дараа ч санаж үлддэг үзэгдэл юм.
Scope-аас эхлэх
Өмнөх хичээлд функц дотор зарласан хувьсагч гаднаас харагдахгүй гэж сурсан. Харин дотор функц гаднах хувьсагчийг харж чадна — энэ бол closure-ын эхлэл.
function outer() {
const message = "Би гаднах функц"; // outer-ийн хувьсагч
function inner() {
console.log(message); // ✅ inner нь message-г харж чадна
}
inner();
}
outer(); // Би гаднах функц
Энэ хэвийн — scope chain-аар ажилладаг. Closure үүсдэг тохиолдол нь дотор функцийг гаднаас буцаах үед.
Closure үүсэх — функц буцаасан функц
function makeCounter() {
let count = 0; // makeCounter-ийн local хувьсагч
return function () {
count++;
console.log(count);
};
}
const counter = makeCounter();
counter(); // 1
counter(); // 2
counter(); // 3
makeCounter() дуусмагц count хувьсагч устах ёстой — гэтэл устаагүй! Буцаагдсан функц count-д хандах эрхийг хадгалсаар байна. Энэ бол closure.
counter бол makeCounter-ийн count хувьсагчийг санаж буй функц. Тус тусдаа makeCounter() дуудах бүрт шинэ, бие даасан count үүсдэг:
const counter1 = makeCounter();
const counter2 = makeCounter();
counter1(); // 1
counter1(); // 2
counter2(); // 1 ← counter2-ийн өөрийн count — counter1-д нөлөөлөхгүй
counter1(); // 3
Closure-ын практик хэрэглээ
Closure нь хувийн (private) өгөгдөл үүсгэхэд хэрэглэгддэг — гаднаас шууд хандаж өөрчлөх боломжгүй, зөвхөн зөвшөөрөгдсөн функцээр дамжуулан удирдагдана.
function createPlayer(name) {
let xp = 0; // private — гаднаас шууд харагдахгүй
let level = 1; // private
return {
addXP: function (amount) {
xp += amount;
if (xp >= level * 100) {
level++;
console.log(`🎉 ${name} түвшин ахиллаа! Одоо ${level}-р түвшин.`);
}
},
getStats: function () {
console.log(`${name} — Түвшин: ${level}, XP: ${xp}`);
},
};
}
const player = createPlayer("Болд");
player.addXP(60);
player.getStats(); // Болд — Түвшин: 1, XP: 60
player.addXP(50);
// 🎉 Болд түвшин ахиллаа! Одоо 2-р түвшин.
player.getStats(); // Болд — Түвшин: 2, XP: 110
console.log(player.xp); // undefined — шууд хандаж болохгүй
console.log(player.level); // undefined — хамгаалагдсан
Closure ба давталт — нийтлэг алдаа
Closure-тай холбоотой нийтлэг нэг алдааг ойлгох нь чухал:
// ❌ var ашиглах — бүгд нэг i-г хуваалцана
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i); // Бүгд 3 хэвлэнэ!
}, 100);
}
// 3, 3, 3
// ✅ let ашиглах — блок scope, closure тус бүр өөр i-тэй
for (let i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i); // 0, 1, 2
}, 100);
}
// 0, 1, 2
let нь давталт бүрд шинэ i үүсгэдэг учраас closure тус бүр өөр өөр i-г санана. Энэ бол let-г var-ын оронд ашиглах чухал шалтгаануудын нэг.
Дараагийн хичээлд:
Массив (Array) — олон утгыг дарааллаар хадгалах өгөгдлийн бүтцийг судлана. Үүсгэх, нэмэх, хасах, индексээр хандах бүгдийг үзнэ.