JavaScript
Import / Export
ES export — export { }
เรียนรู้ ES module export พื้นฐาน — export { } และ export inline เพื่อกำหนดค่าที่ให้ module อื่น import ได้
ES Module Export คืออะไร — ทำไมต้อง export
ในบท import-module เราเรียนวิธีดึงค่าจาก module อื่นมาใช้ แต่ยังไม่ได้เรียนว่าค่าเหล่านั้นมาจากไหน บทนี้เราจะเรียนฝั่งตรงข้าม — วิธี **export** ค่าจาก module ของเราเอง ให้ module อื่นสามารถ import ไปใช้ได้ ลองคิดดู: ถ้าทุก module export ไม่ได้ module อื่นก็ import อะไรไม่ได้ — export คือการ "เปิดประตู" ให้ module อื่นมาใช้งาน บทนี้เราจะเรียน **named export** แบบพื้นฐาน — syntax คือ `export { ชื่อ }` หรือ `export ตอนประกาศ` ซึ่งตรงข้ามกับที่เราใช้ในบท import-module: `import { ชื่อ } from './file.js'` (ส่วน default export, re-export, และ barrel file — เรียนในบท export-advanced)
// ❌ ก่อน — ทุกอย่างอยู่ในไฟล์เดียว ไม่สามารถใช้ซ้ำได้
// ไฟล์: app.js
function calculateTax(price) {
return price * 0.07;
}
function formatCurrency(amount) {
return "฿" + amount.toFixed(2);
}
// ถ้าอยากใช้ฟังก์ชันเหล่านี้ในไฟล์อื่น? ทำไม่ได้!
// ต้อง copy โค้ดไปวางซ้ำ หรือ merge ทุกอย่างในไฟล์เดียว
// ✅ หลัง — แยกไฟล์และ export ให้ไฟล์อื่นใช้ได้
// ไฟล์: math.js — export ฟังก์ชันคำนวณ
export function calculateTax(price) {
return price * 0.07;
}
// ไฟล์: format.js — export ฟังก์ชันจัดรูปแบบ
export function formatCurrency(amount) {
return "฿" + amount.toFixed(2);
}
// ไฟล์: app.js — import มาใช้ (เรียนบท import-module)
import { calculateTax } from './math.js';
import { formatCurrency } from './format.js';
let total = calculateTax(1000);
console.log(formatCurrency(total));
// output: "฿70.00"- **Export** คือการประกาศว่าอะไรใน module นั้นให้ไฟล์อื่น import ได้ — เปรียบเหมือน "เปิดสาธารณะ" ค่าให้ module อื่นมาใช้
- **Import** คือการดึงค่าจาก module ที่ export ไว้แล้ว — เรียนไปแล้วในบท import-module
- Module หนึ่งสามารถ export ได้หลายค่า — ฟังก์ชัน ตัวแปร object array หรืออะไรก็ได้
- Export เฉพาะสิ่งที่จำเป็น — ไม่ต้อง export ทุกอย่างใน module
syntax พื้นฐาน — export { }
รูปแบบพื้นฐานของ `export` สำหรับ named export คือ: `export { ชื่อ1, ชื่อ2, ... };` มี 2 วิธีในการ export: 1. **Export แยกหลังประกาศ** — `export { name1, name2 };` 2. **Export ตอนประกาศ** — `export const name = ...;` หรือ `export function name() {...}` มาแยกส่วนประกอบทีละตัว:
// ส่วนประกอบของ export statement (แบบแยกหลังประกาศ):
//
// ① keyword ② curly braces ③ semicolon
// ↓ ↓ ↓
// export { calculateTax, PI };
// ↑ ↑
// ชื่อที่ export ปิด statement
// (ต้องประกาศไว้ก่อนแล้ว)
// ตัวอย่าง: ประกาศก่อน แล้ว export ทีหลัง
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
const PI = 3.14159;
// export ทีหลัง — รวมในบรรทัดเดียว
export { add, multiply, PI };
// ไฟล์อื่นสามารถ import ได้แล้ว:
// import { add, multiply, PI } from './math.js';
// console.log(PI); // 3.14159
// console.log(add(5, 3)); // 8- `export` — keyword บอก JavaScript ว่ากำลังเปิดค่าให้ module อื่นใช้
- `{ }` — ใส่ชื่อที่ต้องการ export — ต้องประกาศไว้ **ก่อน** แล้ว (function const let var)
- ลงท้ายด้วย `;` — ใช่! export statement ต้องลงท้ายด้วย semicolon
- ชื่อใน `{ }` จะถูก import ใช้ชื่อเดิม — เรียกว่า **named export**
- ตัวเล็กตัวใหญ่ต้องตรงกับที่ประกาศไว้ — case-sensitive
export หลายตัวในบรรทัดเดียว
เวลาต้องการ export หลายค่า คุณไม่ต้องเขียน `export` ทีละบรรทัด — รวมไว้ใน `{ }` เดียวกันได้เลย คั่นด้วย `,`
// ประกาศฟังก์ชันและตัวแปรต่าง ๆ
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
function multiply(a, b) {
return a * b;
}
const PI = 3.14159;
const E = 2.71828;
// ❌ export แยกบรรทัด — ยืดเยื้อไม่จำเป็น
export { add };
export { subtract };
export { multiply };
export { PI };
export { E };
// ✅ รวมในบรรทัดเดียว — อ่านง่ายกว่า
export { add, subtract, multiply, PI, E };
// ไฟล์อื่น import ได้ทันที:
// import { add, subtract, multiply, PI, E } from './math.js';- Export ทุกสิ่งที่ต้องการให้ module อื่นใช้ใน `export` บรรทัดเดียว — คั่นด้วย `,`
- Export เฉพาะสิ่งที่จำเป็น — ไม่ต้อง export ตัวแปร private ภายใน module
- ชื่อใน `{ }` ต้องตรงกับที่ประกาศไว้ — case-sensitive
- ลำดับของชื่อใน `{ }` ไม่สำคัญ — เขียน `add` ก่อน `PI` หรือ `PI` ก่อน `add` ก็ได้ผลเหมือนกัน
export แบบ inline ตอนประกาศ
นอกจาก export แยกหลังจากประกาศแล้ว เรายังสามารถ **export ตอนประกาศ** ได้ด้วย — วิธีนี้กระชับและอ่านง่ายกว่าสำหรับฟังก์ชันหรือตัวแปรที่ export เลยตั้งแต่แรก
// วิธีที่ 1: export แยกหลังประกาศ (เรียนไปแล้ว)
function add(a, b) {
return a + b;
}
const PI = 3.14159;
export { add, PI };
// วิธีที่ 2: export ตอนประกาศ (inline export)
// วาง `export` ไว้หน้าคำสั่งประกาศตัวแปร
export function add(a, b) {
return a + b;
}
export const PI = 3.14159;
export const E = 2.71828;
export let counter = 0;
export const user = { name: "John", age: 30 };
export const numbers = [1, 2, 3, 4, 5];
// ทั้ง 2 วิธีมีผลเหมือนกัน — ไฟล์อื่น import ได้ทันที:
// import { add, PI, E, counter, user, numbers } from './file.js';- **`export function`** — export ฟังก์ชันตอนประกาศ — ใช้เมื่อ export เลยตั้งแต่แรก
- **`export const`** — export constant ตอนประกาศ — ใช้เมื่อ export เลยตั้งแต่แรก
- **`export let`** — export let variable ตอนประกาศ — ใช้เมื่อต้องการให้ไฟล์อื่นแก้ค่าได้
- ไม่ต้องปิดด้วย `;` ถ้า export ตอนประกาศแบบฟังก์ชัน
- เลือกวิธีที่เหมาะกับสถานการณ์ — ถ้า export เลยตั้งแต่แรกใช้ inline ถ้าต้องรวมในท้ายไฟล์ใช้ export แยก
**เมื่อไหร่ควรใช้วิธีไหน?** - **ใช้ export แยก (`export { }`)** เมื่อ: - ต้องการรวม export ทั้งหมดไว้ท้ายไฟล์ — ดูง่ายว่า module นี้ export อะไรบ้าง - มี logic ที่ซับซ้อนก่อนถึงจะถึงส่วน export - **ใช้ export inline (`export function`, `export const`)** เมื่อ: - export เลยตั้งแต่แรก — อ่านง่ายว่าฟังก์ชันนี้สามารถถูก import ได้ - ไฟล์เล็กและ export ไม่เยอะ - ต้องการความกระชับ — ไม่ต้องเขียน export ซ้ำ
ข้อควรระวังและความเข้าใจผิดที่พบบ่อย
มือใหม่ที่เริ่มใช้ `export` มักเจอ error แปลก ๆ ที่เกิดจากการเขียนไม่ถูก syntax — มาดูเรื่องที่พบบ่อยและวิธีแก้:
| เรื่องที่เข้าใจผิด / ทำผิด | สิ่งที่เกิดขึ้นจริง | วิธีแก้ |
|---|---|---|
| export ชื่อที่ยังไม่ประกาศ | `ReferenceError` หรือค่าที่ export ไม่มีอยู่จริง | ต้องประกาศค่าก่อนแล้วค่อย export — `const name = ...; export { name };` |
| export ชื่อเดียวกัน 2 ครั้ง | `SyntaxError` หรือ `TypeError` — duplicate export | export ชื่อเดียวกันได้ครั้งเดียว — ลบ export ที่ซ้ำออก |
| ใช้ export แต่ import ผิดชื่อ (case) | `SyntaxError: does not provide an export named 'Add'` | เช็คตัวเล็กตัวใหญ่ให้ตรงกับที่ export — `add` กับ `Add` คนละตัวกัน |
| ลืมใส่ `{ }` รอบชื่อ export | `SyntaxError` — export syntax error | ใช้ `export { name }` มี `{ }` เสมอ (ยกเว้น export inline) |
| export แล้วแก้ค่า let ใน module เอง | ไฟล์อื่นที่ import อยู่จะเห็นค่าที่เปลี่ยนไปทันที | ระวัง shared state — let export ที่ถูกหลายไฟล์ import คือ shared state |
// ❌ export ชื่อที่ยังไม่ประกาศ
export { notDeclared };
// ❌ ReferenceError: notDeclared is not defined
// ❌ export ชื่อเดียวกัน 2 ครั้ง
const count = 0;
export { count };
export { count };
// ❌ SyntaxError: duplicate export 'count'
// ❌ ใส่ export หลังประกาศแล้ว export inline ซ้ำ
function add(a, b) {
return a + b;
}
export { add };
export function add(a, b) {
return a + b;
}
// ❌ SyntaxError: duplicate export 'add'
// ✅ ถูกต้อง — export วิธีเดียวเลือกวิธีเดียว
function add(a, b) {
return a + b;
}
const PI = 3.14159;
export { add, PI };**Shared state ความเสี่ยงที่ต้องรู้:** เมื่อคุณ export `let` variable และไฟล์อื่น import มันไป ทุกไฟล์ที่ import จะเห็นค่าเดียวกัน — ไม่ใช่ copy แยก ```javascript // counter.js export let count = 0; function increment() { count++; } export { increment }; // main.js import { count, increment } from './counter.js'; console.log(count); // 0 increment(); console.log(count); // 1 // other.js ก็จะเห็นค่าเดียวกัน import { count } from './counter.js'; console.log(count); // 1 ``` นี่คือ **shared state** — ถ้าไฟล์อื่นก็แก้ `count` ไฟล์ของคุณจะเห็นค่าที่เปลี่ยนไปทันที ทางปลอดภัย: export `const` เท่านั้น หรือใช้ฟังก์ชันที่ไม่เปลี่ยนค่าตรง ๆ
สรุป — ES export พื้นฐาน
- **Export** คือการประกาศว่าอะไรใน module นั้นให้ไฟล์อื่น import ได้ — เปิดประตูให้ module อื่นใช้
- **`export { name1, name2 }`** — syntax สำหรับ export แยกหลังประกาศ — รวม export หลายตัวได้ในบรรทัดเดียว
- **`export function`, `export const`** — syntax สำหรับ export ตอนประกาศ — กระชับและอ่านง่ายกว่า
- **ชื่อใน export** ต้องตรงกับที่ประกาศไว้ — case-sensitive
- **export หลายตัว** — ใช้ `export { a, b, c }` รวมในบรรทัดเดียวคั่นด้วย `,`
- **ห้าม export ชื่อเดียวกัน 2 ครั้ง** — จะ error duplicate export
- **shared state** — export `let` คือ shared state ไฟล์ทุกไฟล์จะเห็นค่าเดียวกัน
- **import vs export** — import ดึงค่าจาก module อื่น export ประกาศค่าที่ module อื่นดึงได้
| สิ่งที่อยากรู้ | คำตอบสั้น |
|---|---|
| export syntax (แยก) | `export { name1, name2 };` |
| export syntax (inline) | `export function name() {}` หรือ `export const name = ...;` |
| export หลายตัว | รวมใน `{ }` คั่นด้วย `,` |
| export ซ้ำ | ห้าม — จะ error duplicate export |
| shared state | export `let` คือ shared state ใช้ `const` ปลอดภัยกว่า |
| import vs export | import ดึงค่ามา export เปิดค่าให้ไฟล์อื่นดึงได้ |
| advanced export | default export, re-export, barrel — เรียนบท export-advanced |
ลองทำ — สร้าง module และ export ให้ถูกต้อง
ถึงเวลาลองใช้ `export` ด้วยตัวเองแล้ว! เราจะสร้าง project เล็ก ๆ ประกอบด้วย **3 ไฟล์**: 1. **`math.js`** — module ที่เราจะ export ฟังก์ชันและค่าคงที่ 2. **`main.js`** — ไฟล์หลักที่ import และใช้งาน 3. **`index.html`** — หน้าเว็บที่โหลด `main.js` ผ่าน `<script type="module">` เปิด editor ของคุณ สร้าง folder ใหม่ (ตั้งชื่ออะไรก็ได้ เช่น `my-first-export`) แล้วสร้างไฟล์ตามด้านล่าง
// math.js — module ที่ export ฟังก์ชันคำนวณ
// ประกาศฟังก์ชันก่อน
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
function multiply(a, b) {
return a * b;
}
function divide(a, b) {
return a / b;
}
// ประกาศค่าคงที่
const PI = 3.14159;
const E = 2.71828;
// export ทุกอย่างที่ต้องการให้ไฟล์อื่นใช้
export { add, subtract, multiply, divide, PI, E };// main.js — import ฟังก์ชันจาก math.js มาใช้
import { add, subtract, multiply, divide, PI, E } from './math.js';
console.log("ค่าคงที่:");
console.log("PI =", PI);
console.log("E =", E);
console.log("\nการบวก:");
console.log("5 + 3 =", add(5, 3));
console.log("10 + 20 =", add(10, 20));
console.log("\nการลบ:");
console.log("10 - 5 =", subtract(10, 5));
console.log("100 - 75 =", subtract(100, 75));
console.log("\nการคูณ:");
console.log("7 × 6 =", multiply(7, 6));
console.log("PI × 2 =", multiply(PI, 2));
console.log("\nการหาร:");
console.log("20 ÷ 4 =", divide(20, 4));
console.log("E ÷ 2 =", divide(E, 2));
console.log("\nผสมผสาน:");
console.log("(5 + 3) × 2 =", multiply(add(5, 3), 2));
console.log("(10 - 5) ÷ 2.5 =", divide(subtract(10, 5), 2.5));<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<title>My First Export</title>
</head>
<body>
<h1>เปิด Console (F12) เพื่อดูผลลัพธ์</h1>
<script type="module" src="main.js"></script>
</body>
</html>ไฟล์ทั้ง 3 ต้องอยู่ใน **folder เดียวกัน** โครงสร้างจะเป็นแบบนี้: ``` my-first-export/ ├── math.js ├── main.js └── index.html ``` **วิธีรัน**: คลิกขวาที่ `index.html` ใน VS Code → เลือก **"Open with Live Server"** เบราว์เซอร์จะเปิดแท็บใหม่ จากนั้นกด **F12** เพื่อเปิด Console ⚠️ ห้ามเปิดไฟล์ HTML ตรง ๆ จาก file explorer — ต้องรันผ่าน **Live Server** เท่านั้น (URL ต้องเป็น `http://127.0.0.1:...`)
ค่าคงที่:
PI = 3.14159
E = 2.71828
การบวก:
5 + 3 = 8
10 + 20 = 30
การลบ:
10 - 5 = 5
100 - 75 = 25
การคูณ:
7 × 6 = 42
PI × 2 = 6.28318
การหาร:
20 ÷ 4 = 5
E ÷ 2 = 1.35914
ผสมผสาน:
(5 + 3) × 2 = 16
(10 - 5) ÷ 2.5 = 2- ถ้า console **ไม่แสดงอะไรเลย** → เช็คว่า `index.html` มี `type="module"` ใน `<script>` หรือยัง
- ถ้า console **แดง error** → อ่านข้อความ error ดู — ส่วนใหญ่เกิดจาก path ผิด (ลืม `./` หรือลืม `.js`) หรือ export ไม่ถูกต้อง
- ถ้า console **แดง CORS error** → เปิดไฟล์ตรง ๆ ไม่ได้ผ่าน Live Server — ต้องใช้ Live Server
- ถ้าเห็นผลลัพธ์ครบตามด้านบน → **ผ่านแล้ว!** export ทำงานถูกต้อง
เห็นผลลัพธ์ครบแล้ว? ลอง **ทดลองเปลี่ยนโค้ด** เพื่อทำความเข้าใจให้ลึกขึ้น: - ใน `math.js` ลอง **export แค่บางตัว** — เช่น `export { add, multiply };` แล้วใน `main.js` ลอง import ตัวที่ไม่ได้ export ดู error - ใน `math.js` ลอง **export ชื่อเดียวกัน 2 ครั้ง** — เช่น `export { add };` แล้ว export ซ้ำอีกครั้ง - ใน `math.js` ลอง **เปลี่ยนเป็น export inline** — เปลี่ยน `function add` เป็น `export function add` แล้วลบ `export { }` ท้ายไฟล์ - ใน `main.js` ลอง **import ชื่อผิด case** — เปลี่ยน `add` เป็น `Add` (ตัวใหญ่) แล้ว refresh ดู error เห็น error แล้วจำไว้ — พวกนี้คือ error ที่มือใหม่เจอบ่อยที่สุด รู้จักหน้าตาไว้จะช่วยแก้ไขได้เร็วขึ้น