Skip to content

บทที่ 10 — Modules: แบ่งโค้ดเป็นไฟล์

← บทที่ 09 | สารบัญ | บทที่ 11: Error Handling →

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

อ่านจบบทนี้คุณจะ:

  • เข้าใจว่าทำไมต้องแบ่งโค้ดเป็น module
  • ใช้ import / export เป็น
  • เข้าใจความต่างระหว่าง ESM กับ CommonJS
  • ใช้ dynamic import เพื่อโหลด module ตามต้องการ

ใช้เวลา 2 ชั่วโมง


Part 1: ทำไมต้องมี Module

1.1 ปัญหาของโค้ดไฟล์เดียว

ลองนึกโปรแกรมจริง — มันมีโค้ดเป็นพันเป็นหมื่นบรรทัด ถ้าเขียนในไฟล์เดียว:

  • หาโค้ดไม่เจอ — เลื่อนหา function ในไฟล์ 5000 บรรทัด
  • ชื่อชนกัน — มีตัวแปร data หลายที่ ทับกันโดยไม่ตั้งใจ
  • แก้แล้วพังที่อื่น — ไม่รู้ว่าโค้ดส่วนไหนเกี่ยวกับส่วนไหน
  • ทำงานเป็นทีมไม่ได้ — ทุกคนแก้ไฟล์เดียวกัน conflict ตลอด

1.2 ทางแก้ — Module

Module = การแบ่งโค้ดออกเป็นไฟล์ ๆ โดยแต่ละไฟล์ "ประกาศ" ว่าจะแชร์อะไรออกไป และ "ขอใช้" อะไรจากไฟล์อื่น

หลักการ:

  • 1 ไฟล์ = 1 module
  • แต่ละ module มี "ของส่วนตัว" (ตัวแปร function ในไฟล์) ที่ไฟล์อื่นมองไม่เห็น
  • module export สิ่งที่อยากแชร์
  • module อื่น import สิ่งที่ต้องการมาใช้

💡 เปรียบเทียบ: module เหมือน "แผนกในบริษัท" — แต่ละแผนกทำงานของตัวเอง มีของส่วนตัว — แต่มี "หน้าต่างบริการ" (export) ให้แผนกอื่นมาขอใช้ — และแผนกอื่นก็มา "ยื่นเรื่อง" (import) ขอบริการ


Part 2: ES Modules (ESM) — มาตรฐานสมัยใหม่

JavaScript สมัยใหม่ใช้ระบบ module ชื่อ ES Modules (ESM) — ใช้คำสั่ง import / export

2.1 Export — แชร์ออกไป

มี 2 แบบ — named export และ default export

Named Export — แชร์หลายอย่าง (มีชื่อ)

javascript
// ไฟล์: math.js

export const PI = 3.14159;

export function add(a, b) {
  return a + b;
}

export function multiply(a, b) {
  return a * b;
}

ใส่ export หน้าสิ่งที่อยากแชร์ — แชร์ได้หลายอย่าง

หรือ export รวมท้ายไฟล์:

javascript
const PI = 3.14159;
function add(a, b) { return a + b; }
function multiply(a, b) { return a * b; }

export { PI, add, multiply };          // export รวมทีเดียว

Default Export — แชร์ "ของหลัก" 1 อย่าง

javascript
// ไฟล์: User.js

export default class User {
  constructor(name) {
    this.name = name;
  }
}

default = "ของหลักของไฟล์นี้" — มีได้ไฟล์ละ 1 อันเท่านั้น

2.2 Import — ขอมาใช้

Import Named Export

javascript
// ไฟล์: main.js

import { add, PI } from "./math.js";

console.log(add(2, 3));      // 5
console.log(PI);             // 3.14159

ชื่อใน { } ต้องตรงกับชื่อที่ export

เปลี่ยนชื่อตอน import ด้วย as:

javascript
import { add as sum } from "./math.js";
console.log(sum(2, 3));      // 5

import ทุกอย่างเป็น object เดียว:

javascript
import * as math from "./math.js";
console.log(math.add(2, 3));
console.log(math.PI);

Import Default Export

javascript
import User from "./User.js";       // ไม่มี { } — และตั้งชื่ออะไรก็ได้

const u = new User("Alice");

default export — ตอน import ไม่ต้องมี { } และตั้งชื่ออะไรก็ได้ (ไม่ต้องตรงกับชื่อตอน export)

Import ทั้ง default และ named

javascript
import User, { PI, add } from "./module.js";
// User = default, PI/add = named

2.3 ⚠️ ความต่าง Named กับ Default

Named ExportDefault Export
จำนวนต่อไฟล์หลายอันได้1 อันเท่านั้น
importต้องมี { }ไม่มี { }
ชื่อตอน importต้องตรง (หรือใช้ as)ตั้งชื่ออะไรก็ได้

→ คำแนะนำ: ใช้ named export เป็นหลัก (ชื่อตรงกันทุกที่ ค้นหาง่าย refactor ง่าย) — ใช้ default เมื่อไฟล์มี "ของหลัก" ชัดเจน 1 อย่าง

2.4 เปิดใช้ ESM

ESM ใช้ได้เมื่อ:

ใน Node.js — ใส่ "type": "module" ใน package.json (จำจากบทที่ 01):

json
{ "type": "module" }

💡 package.json คืออะไร? — ไฟล์ตั้งค่าโปรเจกต์ที่อยู่ที่ root ของโฟลเดอร์ สร้างได้ด้วยคำสั่ง npm init -y ถ้ายังไม่มี (เรียนละเอียดในบทที่ 13)

ในเบราว์เซอร์ — ใส่ type="module" ใน script tag:

html
<script type="module" src="main.js"></script>

Part 3: รายละเอียดของ import/export

3.1 import ต้องระบุ path ให้ถูก

javascript
import { x } from "./math.js";       // ไฟล์ในโฟลเดอร์เดียวกัน — ต้องมี ./
import { x } from "../utils.js";      // โฟลเดอร์แม่ — ../
import { x } from "./lib/helper.js";  // โฟลเดอร์ย่อย
import dayjs from "dayjs";            // library จาก node_modules — ใส่แค่ชื่อ (ไม่มี ./)

💡 ทำไม "dayjs" ใส่แค่ชื่อ ไม่มี ./? — เมื่อ Node.js เห็น path ที่ไม่ขึ้นต้นด้วย ./ หรือ ../ มันจะตีความว่าเป็น "ชื่อ package" แล้วไปหาในโฟลเดอร์ node_modules/ ของโปรเจกต์โดยอัตโนมัติ (เรียก path แบบนี้ว่า "bare specifier")

⚠️ ใน Node.js ESM ต้องใส่นามสกุลไฟล์ครบ./math.js (ไม่ใช่ ./math) — ใช้ทุกตัวอย่างในบทนี้ และทุก import แบบ relative (./ หรือ ../) ต้องลงท้าย .js เสมอ

💡 ถ้ายังไม่ได้เรียน TypeScript — ไม่ต้องสนใจส่วนนี้ ใช้ .js ธรรมดาได้เลย สำหรับผู้ที่เรียน TypeScript: TypeScript ใช้ .js ใน import แม้ไฟล์จริงจะเป็น .ts — อ่านเพิ่มในบท TypeScript

3.2 import ถูก "ยกขึ้นบนสุด" (hoisted)

ในทางเทคนิค — ไม่ว่าจะเขียน import ไว้ตรงไหนในไฟล์ มันถูกประมวลผลก่อนโค้ดอื่นเสมอ (เรียกว่า "hoisting" = การยกขึ้น — คือ JS จะประมวลผลบางส่วนของโค้ดล่วงหน้าก่อนรันตามลำดับบรรทัดจริง เคยเจอเรื่องนี้กับ var และ function declaration ในบทที่ 02/05 แล้ว import ก็ทำงานแบบเดียวกัน คือถูกประมวลผลก่อนโค้ดอื่น) ดังนั้นโค้ดด้านล่างนี้ "รันได้":

javascript
console.log(add(2, 3));              // ใช้ได้ — แม้ import อยู่ข้างล่าง (เพราะ import ถูกยกขึ้น)
import { add } from "./math.js";

→ แต่ในทางปฏิบัติ — เขียน import ไว้บนสุดของไฟล์เสมอ เพื่อให้อ่านง่ายและ ESLint/Prettier ไม่เตือน (มาตรฐานทีมส่วนใหญ่บังคับ)

3.3 Re-export — ส่งต่อ

ไฟล์หนึ่งสามารถ "ส่งต่อ" export ของไฟล์อื่น:

javascript
// ไฟล์: index.js
export { add, multiply } from "./math.js";
export { User } from "./User.js";
export { formatDate } from "./date.js";

แล้วไฟล์อื่น import จากที่เดียว:

javascript
import { add, User, formatDate } from "./index.js";

เทคนิคนี้เรียก "barrel file" (ไฟล์รวม export — รวบ export จากหลายไฟล์ไว้ที่จุดเดียว ให้ import จากที่เดียวได้สะดวก)

⚠️ ข้อควรระวัง: barrel file อาจทำให้ bundler (เครื่องมือรวมไฟล์ — บทที่ 13) ตัดโค้ดที่ไม่ใช้ (tree-shaking — อธิบายเต็มในบทที่ 13) ได้ยากขึ้น เพราะการ import 1 อย่างจาก barrel อาจดึง module อื่น ๆ เข้ามาด้วย — bundler สมัยใหม่อย่าง Vite 5+ จัดการเรื่องนี้ได้ดีขึ้น แต่โปรเจกต์ขนาดใหญ่ควรพิจารณา import ตรงจากไฟล์ต้นทางแทน


Part 4: Module เป็น "ของชิ้นเดียว" (singleton) ที่ใช้ร่วมกัน

เรื่องสำคัญที่ต้องเข้าใจ — module ถูกรันแค่ครั้งเดียว ไม่ว่าจะ import กี่ที่ (singleton = "ของชิ้นเดียว" — มีอยู่ชุดเดียวในทั้งโปรแกรม ทุกที่ที่เรียกใช้ได้ของชุดเดียวกัน)

javascript
// ไฟล์: counter.js
let count = 0;
export function increment() { return ++count; }
export function getCount() { return count; }
javascript
// ไฟล์ a.js
import { increment } from "./counter.js";
increment();
increment();

// ไฟล์ b.js
import { getCount } from "./counter.js";
console.log(getCount());      // 2 — เห็นค่าที่ a.js เพิ่ม!

a.js กับ b.js import counter.js คนละที่ — แต่ใช้ count ตัวเดียวกัน เพราะ module รันครั้งเดียว

→ ใช้ประโยชน์: สร้าง "state ส่วนกลาง" ที่ทุกไฟล์ใช้ร่วมกัน (เช่น config, การตั้งค่า)


Part 5: CommonJS — ระบบ module เก่าของ Node.js (อ่านโค้ดเก่าออก)

📌 สรุปสั้น (ปี 2026): โปรเจกต์ใหม่ทุกตัวควรใช้ ESM — CommonJS เหลือไว้แค่ "อ่านออก" และไว้ทำงานกับโค้ด/package เก่าเท่านั้น Part นี้สอนแค่ระดับ "อ่านโค้ดเก่ารู้เรื่อง"

5.1 syntax ของ CommonJS

ก่อนจะมี ES Modules มาตรฐาน Node.js ใช้ระบบโมดูลของตัวเองชื่อ CommonJS (CJS) — export ด้วย module.exports และนำเข้าด้วย require() ยังเจอในโค้ด Node เก่าและ package จำนวนมาก จึงควรอ่านออก:

javascript
// export (CommonJS)
// ไฟล์: math.cjs   (หรือ math.js ในโปรเจกต์ที่ไม่ใส่ "type": "module")
function add(a, b) { return a + b; }
const PI = 3.14159;

module.exports = { add, PI };
javascript
// import (CommonJS)
// ไฟล์: main.cjs
const { add, PI } = require("./math.cjs");

CommonJS ใช้ module.exports และ require() — ไม่ใช่ export/import

5.2 ESM vs CommonJS

ESM (มาตรฐาน ปี 2026)CommonJS (legacy/interop)
exportexportmodule.exports
importimportrequire()
ใช้ในเบราว์เซอร์✅ ได้❌ ไม่ได้
วิเคราะห์โครงสร้างก่อนรัน (static — รองรับ tree-shaking ดูบทที่ 13)ตอนรัน (dynamic — require() คือ function ธรรมดา)
มาตรฐาน ECMAScript✅ มาตรฐานทางการ❌ เฉพาะ Node.js
top-level await✅ ใช้ได้❌ ไม่ได้

⚠️ หมายเหตุเรื่อง "static vs dynamic": ทั้งคู่ "รัน" ตอนรันไทม์เหมือนกัน ความต่างคือ ESM วิเคราะห์โครงสร้าง import/export ได้ตั้งแต่ก่อนรัน (เพราะ syntax เป็นคีย์เวิร์ดเฉพาะ) — bundler เลย tree-shake (ตัดโค้ดที่ไม่ได้ใช้) ได้ ส่วน CJS require() เป็น function ธรรมดา จะรู้ได้ตอนรันถึงบรรทัดนั้นเท่านั้น

กฎปี 2026: โปรเจกต์ใหม่ ใช้ ESM ตลอด — รู้จัก CommonJS ไว้เพื่อ (1) อ่านโค้ดเก่าออก (2) ทำงานกับ package เก่าที่ยังเป็น CJS อยู่

5.3 Interop — เรียก ESM จาก CJS และกลับกัน (Node 22+)

ความจริงอย่างหนึ่งคือ ecosystem ของ Node ยังมี CJS package เยอะ — Node เลยมีระบบให้ใช้ข้ามกันได้:

จาก ESM ไป CJS — ใช้ import ได้ตรง ๆ:

javascript
// ไฟล์ ESM
import legacy from "some-cjs-package";   // ได้ default export = module.exports

จาก CJS ไป ESM (เดิม): ต้องใช้ await import() (dynamic import) เท่านั้น — require() ตรง ๆ ไม่ได้

Node.js เวอร์ชันใหม่ ๆ มีฟีเจอร์ require(esm) — ใช้ require() กับไฟล์ ESM ได้โดยตรง (ตราบใดที่ไฟล์นั้นไม่มี top-level await):

javascript
// CJS ใน Node.js เวอร์ชันที่รองรับ require(esm)
const { add } = require("./math.js");    // math.js เป็น ESM ก็เรียกได้

⚠️ หมายเหตุเวอร์ชัน: เวอร์ชันที่แน่นอนที่ฟีเจอร์นี้ทำงานได้โดยไม่ต้องใส่ flag อาจเปลี่ยนแปลงได้ — ตรวจสอบสถานะ/เวอร์ชันล่าสุดก่อนใช้ (เช่นดูจาก release notes ของ Node.js) และรันคำสั่ง node --version เพื่อดูว่าเครื่องใช้เวอร์ชันไหนอยู่

ฟีเจอร์นี้ช่วยให้การ migrate จาก CJS ไป ESM ค่อย ๆ ทำได้ — ไม่ต้องเปลี่ยนทั้งโปรเจกต์ในรอบเดียว แต่โปรเจกต์ใหม่ก็ยังควรเป็น ESM ตั้งแต่แรก


Part 6: Dynamic Import — โหลดตามต้องการ

ความต่างระหว่าง static กับ dynamic:

  • static (ตายตัวล่วงหน้า) = import ... from "..." ที่เขียนไว้บนสุดของไฟล์ — โหลดทันทีตั้งแต่โปรแกรมเริ่ม
  • dynamic (โหลดตอนรัน) = import(...) แบบ function — ตัดสินใจตอนโค้ดทำงานจริงว่าจะโหลดหรือไม่

import ปกติ (static) ต้องเขียนบนสุดของไฟล์ และโหลดทันที — แต่บางครั้งเราอยาก "โหลดเมื่อต้องการ" เท่านั้น

ใช้ dynamic importimport() ใช้แบบ function:

javascript
async function loadFeature() {
  const module = await import("./heavyFeature.js");
  module.doSomething();
}

// โหลดเฉพาะตอนผู้ใช้คลิกปุ่ม
// (addEventListener = ผูก function ให้ทำงานเมื่อเกิด event — เรียนละเอียดในบทที่ 12)
button.addEventListener("click", loadFeature);

import() คืน Promise (จำบทที่ 09) → ใช้ await

ประโยชน์ — ไม่ต้องโหลดโค้ดที่ยังไม่ใช้:

  • หน้าเว็บโหลดเร็วขึ้น (โหลดแค่โค้ดที่จำเป็นตอนแรก)
  • โค้ดส่วนที่ใหญ่ ๆ โหลดเมื่อผู้ใช้ต้องการจริง

นี่คือเทคนิค "code splitting" (แตกโค้ดเป็นชิ้น ๆ เพื่อโหลดเฉพาะที่ต้องใช้) — bundler สมัยใหม่ (บทที่ 13) ใช้เทคนิคนี้


Part 7: ESM ในเบราว์เซอร์

7.1 ใช้งานพื้นฐาน

เบราว์เซอร์รองรับ ES Modules โดยตรง — แค่ใส่ type="module" ใน <script> แล้วไฟล์นั้นก็ import ไฟล์อื่นได้ (ต้องระบุ ./ และนามสกุล .js เต็ม):

html
<script type="module" src="main.js"></script>

ใน main.js import ไฟล์อื่นได้:

javascript
import { greet } from "./greet.js";    // ต้องมี ./ และ .js
greet();

7.2 ความพิเศษของ module script

<script type="module"> ต่างจาก <script> ธรรมดา:

  • รันแบบ defer อัตโนมัติ — รอ HTML โหลดเสร็จก่อน (จำ defer จากบทที่ 01)
  • อยู่ใน strict mode อัตโนมัติ
  • ตัวแปรไม่รั่วออก global

7.3 ⚠️ import library ในเบราว์เซอร์

javascript
import _ from "lodash";          // ❌ เบราว์เซอร์ไม่รู้จัก "lodash" (ตามค่าเริ่มต้น)

เบราว์เซอร์โดยปกติรู้จักแค่ path ที่ขึ้นต้นด้วย ./, ../, หรือ URL เต็มเท่านั้น — ส่วน "bare specifier" (ชื่อ package เปล่า ๆ อย่าง "lodash") มันไม่รู้ว่าจะไปหาที่ไหน

มี 3 วิธีแก้:

  1. ใช้ URL เต็ม — โหลดตรงจาก CDN: import _ from "https://esm.sh/lodash"
  2. ใช้ Import Map — บอกเบราว์เซอร์ว่า "lodash" หมายถึงอะไร (เบราว์เซอร์สมัยใหม่รองรับทุกตัวแล้ว):
    html
    <script type="importmap">
    { "imports": { "lodash": "https://esm.sh/lodash" } }
    </script>
    <script type="module">
      import _ from "lodash";    // ✅ ใช้ได้แล้ว
    </script>
  3. ใช้ bundler (เครื่องมือรวมไฟล์ JS อย่าง Vite, esbuild — บทที่ 13) — มันแปลง "lodash" ให้เป็น path ที่เบราว์เซอร์รู้จักตอน build

→ ในงานจริงส่วนใหญ่ — ใช้ bundler เพราะมันจัดการเรื่องนี้และอื่น ๆ ให้ครบ (minify, tree-shaking ฯลฯ — ดูบทที่ 13) ส่วน import map เหมาะกับงานเล็ก/prototype ที่ไม่อยาก setup bundler


Part 8: รูปแบบการจัดโครงสร้างไฟล์

8.1 จัดกลุ่มตามความรับผิดชอบ

เมื่อโปรเจกต์โต ควรแยกไฟล์เป็นโฟลเดอร์ตาม "หน้าที่" (utils, models, services) เพื่อให้หาของเจอและดูแลง่าย โครงสร้างด้านล่างเป็นแบบที่นิยม:

text
src/
├── main.js              # จุดเริ่มต้น
├── utils/
│   ├── math.js
│   ├── date.js
│   └── string.js
├── models/
│   ├── User.js
│   └── Product.js
└── services/
    └── api.js

8.2 ตัวอย่าง — module ที่ออกแบบดี

javascript
// utils/math.js — module ของ pure function
export function add(a, b) { return a + b; }
export function clamp(value, min, max) {
  return Math.max(min, Math.min(max, value));
}
javascript
// services/api.js — module ที่จัดการเรื่อง API
const BASE_URL = "https://api.example.com";

export async function getUser(id) {
  const response = await fetch(`${BASE_URL}/users/${id}`);
  return response.json();
}

export async function getProducts() {
  const response = await fetch(`${BASE_URL}/products`);
  return response.json();
}
javascript
// main.js — รวมทุกอย่าง
// หมายเหตุ: ไฟล์นี้ใช้ top-level await — ต้องเป็น ES module
// (ตั้ง "type": "module" ใน package.json หรือใช้นามสกุล .mjs)
import { getUser } from "./services/api.js";
import { clamp } from "./utils/math.js";

const user = await getUser(1);
console.log(user);

หลักการออกแบบ module ที่ดี:

  • 1 module = 1 ความรับผิดชอบ (math ก็เรื่องเลข, api ก็เรื่อง API)
  • export เฉพาะสิ่งที่จำเป็น — ของที่เป็นรายละเอียดภายในไม่ต้อง export
  • ตั้งชื่อไฟล์ให้สื่อความหมาย

Part 9: Lab — ลงมือทำ

Lab 1: สร้าง module แรก

ฝึกแยกโค้ดเป็น module — สร้าง math.js ที่ export ฟังก์ชัน/ค่าออกไป แล้ว import มาใช้ใน main.js:

math.js:

javascript
export function add(a, b) { return a + b; }
export function subtract(a, b) { return a - b; }
export const PI = 3.14159;

main.js:

javascript
import { add, subtract, PI } from "./math.js";

console.log(add(5, 3));        // 8
console.log(subtract(10, 4));  // 6
console.log(PI);               // 3.14159

ขั้นตอนรันตัวอย่างนี้:

  1. สร้างโฟลเดอร์ใหม่ เช่น my-modules
  2. รันคำสั่งนี้ใน terminal: npm init -y เพื่อสร้าง package.json
  3. เปิด package.json แล้วเพิ่ม "type": "module" (หรือแก้ให้มีบรรทัดนี้)
  4. สร้างไฟล์ math.js และ main.js ตามตัวอย่างด้านบน
  5. รันด้วยคำสั่ง: node main.js

Lab 2: Default export

ฝึกใช้ export default (ส่งออกค่าหลักหนึ่งค่าต่อไฟล์) แล้ว import โดยตั้งชื่อเองตอนนำเข้า — ต่างจาก named export ที่ต้องใช้ชื่อตรงกัน:

Calculator.js:

javascript
export default class Calculator {
  constructor() {
    this.result = 0;
  }
  add(n) { this.result += n; return this; }
  subtract(n) { this.result -= n; return this; }
  getResult() { return this.result; }
}

main.js:

javascript
import Calculator from "./Calculator.js";

const calc = new Calculator();
const result = calc.add(10).subtract(3).add(5).getResult();
console.log(result);           // 12

Lab 3: Module เป็น singleton

config.js:

javascript
let settings = { theme: "light", lang: "th" };

export function getSettings() { return settings; }
export function setTheme(theme) { settings.theme = theme; }

a.js:

javascript
import { setTheme } from "./config.js";
setTheme("dark");

main.js:

javascript
import "./a.js";                       // รัน a.js (เปลี่ยน theme)
import { getSettings } from "./config.js";
console.log(getSettings());            // { theme: "dark", lang: "th" }

💡 ทำไมลำดับถึงถูก? — ใน ES Modules module ที่ถูก import จะรันตามลำดับ dependency ก่อนที่โค้ดในไฟล์ปัจจุบันจะเริ่มทำงาน ดังนั้น a.js (ซึ่งเรียก setTheme("dark")) จะรันเสร็จก่อน console.log(getSettings()) เสมอ — ลำดับของ import statement ในไฟล์จึงสำคัญสำหรับ side effects แบบนี้


Part 10: Checkpoint

  1. ทำไมต้องแบ่งโค้ดเป็น module?
  2. Named export ต่าง default export ยังไง?
  3. import named export ต้องมี { } ไหม? default ล่ะ?
  4. ทำไมแนะนำใช้ named export เป็นหลัก?
  5. เปิดใช้ ESM ใน Node.js ทำยังไง?
  6. "Module เป็น singleton" หมายความว่ายังไง?
  7. ESM ต่าง CommonJS ยังไง?
  8. Dynamic import ใช้ตอนไหน? มีประโยชน์อะไร?
  9. ทำไม import library ในเบราว์เซอร์ตรง ๆ ไม่ได้?
  10. Barrel file คืออะไร?

Part 11: สรุปบทนี้

  • Module = แบ่งโค้ดเป็นไฟล์ — แต่ละไฟล์ export สิ่งที่แชร์ และ import สิ่งที่ต้องการ
  • ESM = มาตรฐานสมัยใหม่ — export / import
  • Named export (หลายอัน ต้องมี { }) — ใช้เป็นหลัก
  • Default export (1 อัน ไม่มี { }) — ใช้กับ "ของหลัก" ของไฟล์
  • Module เป็น singleton — รันครั้งเดียว ทุกที่ที่ import ใช้ของเดียวกัน
  • CommonJS (require/module.exports) = ระบบเก่าของ Node — รู้จักไว้อ่านโค้ดเก่า
  • Dynamic import (import()) — โหลด module ตามต้องการ (code splitting)
  • 1 module = 1 ความรับผิดชอบ

บทต่อไป — Error Handling: จัดการข้อผิดพลาด


← บทที่ 09 | สารบัญ | บทที่ 11: Error Handling →