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

ตัวสร้างที่เปลี่ยนแปลงไม่ได้

ส่งคืนอินสแตนซ์ตัวสร้างใหม่เพื่อให้การประกอบปลอดภัยยิ่งขึ้น

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

การเปลี่ยนแปลงค่าเทียบกับการไม่เปลี่ยนแปลงค่า

ตัวสร้างที่ผ่านมาเปลี่ยนแปลงค่าใน this แล้วคืนค่านั้น ตัวสร้างแบบไม่เปลี่ยนแปลงค่าจะคืนอินสแตนซ์ตัวสร้างใหม่ในทุกขั้น โดยไม่เปลี่ยนแปลงตัวเดิมเลย วิธีนี้ทำให้การประกอบปลอดภัยยิ่งขึ้น

ปัญหาของการเปลี่ยนแปลงค่าที่ใช้ร่วมกัน

หากโค้ดสองส่วนถืออ้างอิงตัวสร้างที่เปลี่ยนแปลงค่าได้ตัวเดียวกัน การเรียกเมธอดกำหนดค่าครั้งหนึ่งจะส่งผลต่อทั้งสองส่วน ตัวสร้างแบบไม่เปลี่ยนแปลงค่าจะหลีกเลี่ยงผลกระทบที่ไม่คาดคิดจากการอ้างอิงเดียวกันได้อย่างสมบูรณ์

const base = makeMutableBuilder().url("/x");
// If base is shared, later .method() calls mutate everyone's copy.

การคืนอินสแตนซ์ใหม่

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

class IB<S> {
  constructor(private readonly d: Record<string, unknown> = {}) {}
  with<K extends string, V>(k: K, v: V): IB<S & Record<K, V>> {
    return new IB<S & Record<K, V>>({ ...this.d, [k]: v });
  }
}

การแบ่งปันโครงสร้างด้วยการกระจาย

การกระจาย { ...this.d, [k]: v } จะคัดลอกรายการเดิมและแทนที่คีย์หนึ่งรายการ ค่าที่ไม่เปลี่ยนแปลงจะใช้การอ้างอิงร่วมกัน จึงทำให้การคัดลอกมีต้นทุนต่ำ

const a = new IB<{}>().with("url", "/x");
const c = a.with("method", "GET");
// a still only has url; c has url and method.

ตัวเดิมไม่เคยเปลี่ยนแปลง

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

const base = new IB<{}>().with("url", "/api");
const get = base.with("method", "GET");
const post = base.with("method", "POST");
console.log("base untouched; get and post diverge");

สถานะภายในแบบ readonly

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

class IB<S> {
  constructor(private readonly d: Readonly<Record<string, unknown>> = {}) {}
}

การสร้างแบบไม่เปลี่ยนแปลงค่าที่มีชนิดข้อมูล

พารามิเตอร์สถานะยังคงถูกส่งต่อไปเรื่อย ๆ ดังนั้นเราจึงจำกัด build() ได้เหมือนเดิม โดยมีพื้นฐานเป็นโครงสร้างแบบไม่เปลี่ยนแปลงค่า

interface Out { url: string; method: string }
class IB<S> {
  constructor(private readonly d: Record<string, unknown> = {}) {}
  with<K extends string, V>(k: K, v: V): IB<S & Record<K, V>> {
    return new IB<S & Record<K, V>>({ ...this.d, [k]: v });
  }
  build(this: IB<{ url: string; method: string }>): Out { return this.d as Out; }
}
const out = new IB<{}>().with("url", "/u").with("method", "GET").build();
console.log(out.url);

การประกอบที่ปลอดภัยยิ่งขึ้น

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

ค่าตั้งต้นที่นำกลับมาใช้ได้

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

const jsonBase = new IB<{}>().with("header", "application/json");
const usersReq = jsonBase.with("url", "/users");
const ordersReq = jsonBase.with("url", "/orders");
console.log("two independent requests from one base");

ประเด็นด้านต้นทุน

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

สรุปตัวสร้างแบบเปลี่ยนแปลงและไม่เปลี่ยนแปลงค่า

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

ตรวจสอบอย่างรวดเร็ว

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

ทบทวน

ตัวสร้างแบบไม่เปลี่ยนแปลงค่าจะคืนอินสแตนซ์ใหม่ในแต่ละขั้น โดยใช้การแบ่งปันโครงสร้างด้วย { ...this.d, [k]: v } และไม่เปลี่ยนแปลง this ตัวเดิมยังคงไม่เปลี่ยนแปลง ทำให้ประกอบใช้งานได้อย่างปลอดภัยและสร้างค่าตั้งต้นที่นำกลับมาใช้ได้ โดยมีต้นทุนการจัดสรรเพิ่มขึ้นเพียงเล็กน้อย

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

บทเรียน “ตัวสร้างที่เปลี่ยนแปลงไม่ได้” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “ตัวสร้างที่เปลี่ยนแปลงไม่ได้”

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

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

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

บทเรียน “ตัวสร้างที่เปลี่ยนแปลงไม่ได้” ใช้เวลานานแค่ไหน

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

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

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

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

  1. พื้นฐานรูปแบบ Builder
  2. อินเทอร์เฟซแบบต่อเนื่องด้วยชนิดข้อมูล
  3. การบังคับใช้ขั้นตอนที่จำเป็น
  4. ตัวสร้างที่เปลี่ยนแปลงไม่ได้
← กลับไปที่ TypeScript Academy