Closure คือการรวมระหว่างฟังก์ชันและ lexical environment ที่ฟังก์ชันนั้นถูกประกาศ
function outerFunc() { var name = "TutorialsPoint"; // name is a local variable created by outerFunc return function innerFunc() { // innerFunc() is the inner function, a closure console.log(name); // use variable declared in the parent function }; } let f = outerFunc(); f()outerFunc() สร้างตัวแปร local ชื่อ name และฟังก์ชัน innerFunc() ฟังก์ชัน innerFunc() เป็น inner function ที่ถูกกำหนดภายใน outerFunc() และเข้าถึงได้เฉพาะภายใน body ของ outerFunc()
สังเกตว่า innerFunc() ไม่มีตัวแปร local ของตัวเอง แต่ inner functions เข้าถึงตัวแปรของ outer functions ได้ ดังนั้น innerFunc() เข้าถึง name ที่ประกาศใน parent function outerFunc() ได้
เห็นได้ว่า name ออกจาก scope เมื่อ outerFunc รันเสร็จ แต่ถ้าดูใกล้ๆ innerFunc ที่ถูก return และ assign ให้ f ยังเข้าถึง name ได้ ดังนั้น inner func จึงสร้าง closure over lexical scope ของ outerFunc
การใช้งานจริง
Emulating private methods - ภาษาเช่น Java มี private methods ที่เรียกได้จาก methods ใน class เดียวกัน JavaScript ไม่มี native way แต่สามารถ emulate ได้ด้วย closures
ตัวอย่าง
var counter = (() => { var privateCounter = 0; let changeBy = (val) => privateCounter += val; return { increment: () => changeBy(1), decrement: () => changeBy(-1), value: () => privateCounter }; })(); console.log(counter.value()); counter.increment(); counter.increment(); console.log(counter.value()); counter.decrement(); console.log(counter.value());ผลลัพธ์
0 2 1
ใช้กับ Event Handlers
for(let i = 0; i < 4; i++) { button = buttons[i] button.addEventListener("click", alert(i)) }ถ้ามี 4 ปุ่มใน collection buttons และเพิ่ม event listeners แบบนี้ ทุกการคลิกจะได้ undefined เพราะตอนเรียก i จะไม่ defined แล้ว วิธีแก้คือสร้าง closure over i
for(let i = 0; i < 4; i++) { button = buttons[i] button.addEventListener("click", () => alert(i)) }