לדלג לתוכן

מודולים בג'אווהסקריפט מוסברים

אם פתחתם פרויקט ריאקט כלשהו, הקובץ הראשון שאתם רואים מלא בשורות import בראש, ו-export בתחתית או ליד הצהרות. זה נראה טריוויאלי, אבל מאחורי התחביר הפשוט הזה עומד רעיון שממש שינה איך כותבים ג'אווהסקריפט - מודולים.

הבעיה שמודולים פותרים

בימים הראשונים של ג'אווהסקריפט בדפדפן, כל קובץ שנטען עם תגית script שיתף את אותו "חלל שמות" גלובלי עם כל שאר הקבצים. אם שני קבצים הגדירו משתנה בשם user, אחד היה דורס את השני, בלי אזהרה, בלי שגיאה - סתם באג שקט ומעצבן. ככל שהאתרים גדלו, זה הפך לבלגן בלתי נסבל.

מודולים פותרים את זה בכך שכל קובץ מקבל "חלל" משלו. שום דבר שמוגדר בקובץ לא נגיש לקבצים אחרים, אלא אם במפורש "מייצאים" אותו, ואף קובץ אחר לא "רואה" אותו אלא אם במפורש "מייבא" אותו.

export ו-import - התחביר הבסיסי

יש שני סוגי ייצוא - ייצוא בשם (named export) וייצוא ברירת מחדל (default export).

// math.js - ייצוא בשם, אפשר כמה בקובץ אחד
export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}
// main.js - ייבוא עם אותם שמות בדיוק, בסוגריים מסולסלים
import { add, subtract } from "./math.js";

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

ייצוא ברירת מחדל שונה - יש רק אחד לכל קובץ, והוא לא דורש סוגריים מסולסלים בייבוא:

// UserCard.js - ייצוא ברירת מחדל, בדרך כלל לקומפוננטה הראשית של הקובץ
export default function UserCard() {
  return "...";
}
// main.js - אפשר לתת לו כל שם שרוצים בייבוא
import UserCard from "./UserCard.js";

מתי להשתמש בכל סוג

הכלל הנפוץ בעולם ריאקט הוא לתת לכל קובץ קומפוננטה ייצוא ברירת מחדל אחד - הקומפוננטה עצמה - ולהשתמש בייצוא בשם לפונקציות עזר, קבועים, או כמה קומפוננטות קטנות שקשורות זו לזו באותו קובץ. ייצוא בשם עדיף כשרוצים שהשם שמייבאים יהיה עקבי בכל הפרויקט - זה מונע מצב שבו אותה פונקציה מיובאת בשמות שונים בקבצים שונים ומבלבלת את כולם.

export const API_URL = "https://api.example.com";
export const MAX_RETRIES = 3;

export default function fetchData() {
  // ...
}

import עם שם אחר - as

לפעמים רוצים לייבא משהו בשם אחר מהשם המקורי, למשל כדי למנוע התנגשות עם משתנה קיים:

import { add as addNumbers } from "./math.js";

ייבוא הכל בבת אחת

אפשר לייבא את כל הייצוא בשם של קובץ תחת אובייקט אחד, שימושי כשיש הרבה פונקציות קשורות:

import * as MathUtils from "./math.js";

MathUtils.add(2, 3);
MathUtils.subtract(5, 2);

ESM מול CommonJS - שני עולמות

יש שני "פורמטים" עיקריים של מודולים בעולם JavaScript. מה שראינו עד עכשיו - import/export - נקרא ESM (ECMAScript Modules), והוא התקן הרשמי של השפה, ומה שרואים כמעט תמיד בפרויקטי פרונטאנד וריאקט מודרניים. הפורמט הישן יותר, שעדיין נפוץ בפרויקטי Node.js ישנים, נקרא CommonJS, ונראה כך:

// CommonJS - הפורמט הישן של Node.js
const math = require("./math.js");
module.exports = fetchData;

שני הפורמטים עושים בערך אותו דבר - מחלקים קוד לקבצים עם ממשק ברור בין ייצוא לייבוא - רק בתחביר שונה. כשעובדים עם ריאקט או כלים מודרניים, כמעט תמיד ESM הוא ברירת המחדל, ותוכלו להתעלם מ-CommonJS עד שתיתקלו בפרויקט ישן.

למה חלוקה לקבצים בכלל טובה

מעבר לפתרון בעיית השמות הגלובליים, מודולים מעודדים מבנה קוד בריא. במקום קובץ אחד ענק עם אלפי שורות, כל קובץ מתמקד באחריות אחת ברורה - קומפוננטה, פונקציית עזר, קבועים. זה הופך את הקוד לקל יותר להבין, לבדוק, ולתחזק, כי כדי להבין חלק מסוים אתם צריכים לפתוח רק את הקובץ הרלוונטי, לא לגלול באלף שורות כדי למצוא איפה מוגדר מה.

בקורס צד לקוח מודולים הם חלק בסיסי מהתרגול מהשיעורים הראשונים על ג'אווהסקריפט, כי כל פרויקט ריאקט אמיתי בנוי עליהם.

לסיכום

מודולים נותנים לכל קובץ ג'אווהסקריפט חלל משלו, עם export לחשיפת מה שרוצים לשתף ו-import לשימוש בו בקובץ אחר. ייצוא ברירת מחדל לדבר המרכזי בקובץ, ייצוא בשם לכל השאר. זה הבסיס לכל פרויקט ריאקט מודרני, וכדאי שיהיה נוח לפני שמתחילים לבנות פרויקטים גדולים.

מבולבלים בין import ל-export בפרויקט שלכם? תשתפו בדיסקורד.

הצטרפו לקהילה בדיסקורד