0Pricing
JavaScript Academy · บทเรียน

การที่คลอเชอร์เก็บสถานะ

ทำความเข้าใจสภาพแวดล้อมเชิงศัพท์ของคลอเชอร์

การที่คลอเชอร์เก็บสถานะ เป็นบทเรียน JavaScript Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน JavaScript Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส JavaScript Academy มีบทเรียนทั้งหมด 4 บทเรียน

คลอเชอร์คืออะไร

คลอเชอร์คือฟังก์ชันที่รวมเข้ากับการอ้างอิงตัวแปรจากขอบเขตที่ฟังก์ชันนั้นถูกกำหนด ฟังก์ชันด้านในจะ “จดจำ” ตัวแปรเหล่านั้นได้ แม้ว่าฟังก์ชันด้านนอกจะคืนค่ากลับไปแล้ว

function outer() {
  const message = "hello";
  function inner() {
    console.log(message); // sees outer variable
  }
  inner();
}
outer(); // "hello"

การคืนค่าฟังก์ชันด้านใน

จุดสำคัญจะเกิดขึ้นเมื่อคุณคืนค่าฟังก์ชันด้านใน ฟังก์ชันนั้นยังเข้าถึงตัวแปรของฟังก์ชันด้านนอกได้ แม้ว่า outer จะทำงานเสร็จไปแล้ว

function outer() {
  const message = "remembered";
  return function () {
    console.log(message);
  };
}
const fn = outer();
fn(); // "remembered"

ขอบเขตแบบเล็กซิคัล

คลอเชอร์ทำงานได้เนื่องจากการกำหนดขอบเขตแบบเล็กซิคัล ฟังก์ชันสามารถเข้าถึงตัวแปรที่กำหนดอยู่ในขอบเขตซึ่งล้อมรอบฟังก์ชันนั้นตามโครงสร้างในซอร์สโค้ด ไม่ใช่ขอบเขовต์ที่ฟังก์ชันถูกเรียกใช้

const x = 10;
function show() {
  console.log(x); // resolves where defined
}
function run() {
  const x = 99;
  show(); // still logs 10, not 99
}
run();

การจับตัวแปรด้วยการอ้างอิง

คลอเชอร์จะจับตัวแปรเอง ไม่ใช่ภาพค่าของตัวแปรในขณะนั้น หากตัวแปรเปลี่ยนแปลงภายหลัง คลอเชอร์ก็จะเห็นค่าใหม่

function make() {
  let count = 0;
  const get = () => count;
  count = 5; // changed after get defined
  return get;
}
console.log(make()()); // 5

การเรียกใช้แต่ละครั้งสร้างขอบเขตใหม่

การเรียกใช้ฟังก์ชันด้านนอกแต่ละครั้งจะสร้างชุดตัวแปรใหม่ คลอเชอร์จากการเรียกใช้คนละครั้งจะไม่ใช้สถานะร่วมกัน

function counter() {
  let n = 0;
  return () => ++n;
}
const a = counter();
const b = counter();
console.log(a(), a()); // 1 2
console.log(b());      // 1 (independent)

คลอเชอร์กับพารามิเตอร์

พารามิเตอร์ของฟังก์ชันก็ถูกจับไว้เช่นกัน ทำให้คุณสร้างฟังก์ชันเฉพาะทางจากฟังก์ชันทั่วไปได้

function adder(x) {
  return (y) => x + y;
}
const add5 = adder(5);
console.log(add5(3));  // 8
console.log(add5(10)); // 15

กับดักลูปแบบคลาสสิก

ข้อผิดพลาดที่พบเห็นกันบ่อยคือ การใช้ var ในลูปจะทำให้คลอเชอร์ทั้งหมดใช้ตัวแปรเดียวกัน เมื่อคลอเชอร์เหล่านั้นทำงาน ลูปก็จบไปแล้ว และทุกคลอเชอร์จึงเห็นค่าสุดท้ายเหมือนกัน

const fns = [];
for (var i = 0; i < 3; i++) {
  fns.push(() => i);
}
console.log(fns[0](), fns[1](), fns[2]()); // 3 3 3

แก้ไขด้วย let

let จะสร้างการผูกค่าใหม่ในการวนซ้ำแต่ละครั้ง ดังนั้นคลอเชอร์แต่ละตัวจึงจับ i ของตัวเองไว้ นี่คือวิธีแก้ไขแบบสมัยใหม่

const fns = [];
for (let i = 0; i < 3; i++) {
  fns.push(() => i);
}
console.log(fns[0](), fns[1](), fns[2]()); // 0 1 2

คลอเชอร์ทำให้หน่วยความจำยังคงอยู่

ตราบใดที่คลอเชอร์ยังคงอยู่ ตัวแปรที่คลอเชอร์จับไว้จะไม่สามารถถูกเก็บคืนโดยตัวเก็บขยะได้ โดยทั่วไปเรื่องนี้ไม่มีปัญหา แต่ก็อาจทำให้หน่วยความจำรั่วไหลได้ หากคุณเก็บคลอเชอร์ไว้นานเกินความจำเป็น

function make() {
  const big = new Array(3).fill("data");
  return () => big.length;
}
const f = make();
console.log(f()); // 3 - big stays in memory via f

คลอเชอร์อยู่ทุกที่

ฟังก์ชันเรียกกลับ ตัวจัดการเหตุการณ์ setTimeout เมธอดของอาร์เรย์ และพรอมิส ล้วนพึ่งพาคลอเชอร์เพื่อจดจำบริบท คุณใช้งานสิ่งเหล่านี้อยู่เสมอโดยมักไม่ทันสังเกต

function greet(name) {
  return () => console.log("Hi " + name);
}
[greet("Ada"), greet("Bob")].forEach((fn) => fn());
// Hi Ada
// Hi Bob

ตรวจสอบสถานะที่ถูกจับไว้

คลอเชอร์หลายตัวจากการเรียกใช้ครั้งเดียวกันจะแชร์ตัวแปรที่ถูกจับไว้ชุดเดียวกัน ดังนั้นคลอเชอร์หนึ่งจึงอ่านค่าที่อีกคลอเชอร์หนึ่งเขียนได้

function pair() {
  let value = 0;
  return {
    set: (v) => { value = v; },
    get: () => value
  };
}
const p = pair();
p.set(42);
console.log(p.get()); // 42

ตรวจสอบความเข้าใจอย่างรวดเร็ว

วิธีที่คลอเชอร์จับสถานะไว้

ทบทวน

คลอเชอร์คือฟังก์ชันที่มาพร้อมการอ้างอิงไปยังขอบเขตที่ใช้กำหนดฟังก์ชันนั้น ด้วยขอบเขตแบบเล็กซิคัล คลอเชอร์จึงจดจำตัวแปรภายนอกได้แม้ฟังก์ชันภายนอกจะทำงานเสร็จแล้ว โดยจับตัวแปรเหล่านั้นตามการอ้างอิง ไม่ใช่ตามค่า การเรียกใช้ฟังก์ชันภายนอกแต่ละครั้งจะสร้างขอบเขตที่เป็นอิสระต่อกัน และควรใช้ let เพื่อหลีกเลี่ยงกับดักของลูป คลอเชอร์ทำให้หน่วยความจำที่ถูกจับไว้ยังคงอยู่ และเป็นพลังเบื้องหลังฟังก์ชันเรียกกลับทั่วทั้งระบบ

คำถามที่พบบ่อย

บทเรียน “การที่คลอเชอร์เก็บสถานะ” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การที่คลอเชอร์เก็บสถานะ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส JavaScript Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส JavaScript Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การที่คลอเชอร์เก็บสถานะ”

ทำความเข้าใจสภาพแวดล้อมเชิงศัพท์ของคลอเชอร์ คุณปฏิบัติ JavaScript Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน JavaScript Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน JavaScript Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “การที่คลอเชอร์เก็บสถานะ” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน JavaScript Academy นี้ได้ไหม

ได้ บทเรียน JavaScript Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การที่คลอเชอร์เก็บสถานะ
  2. ตัวแปรส่วนตัวด้วยคลอเชอร์
  3. รูปแบบโมดูล (IIFE)
  4. ฟังก์ชันโรงงาน
← กลับไปที่ JavaScript Academy