تخطَّ إلى المحتوى

الوحدات في JavaScript: import و export

الدرس 27 من 28 · JavaScript

كل برامجك حتى الآن كانت في ملف واحد. هذا مناسب لخمسين سطراً، لكن المشاريع الحقيقية تصل إلى آلاف الأسطر، وملف واحد بهذا الحجم يصعب أن تجد فيه شيئاً. الحل هو الوحدات (Modules): تقسّم الكود إلى ملفات صغيرة، كل ملف مسؤول عن شيء واحد، ويأخذ من الملفات الأخرى ما يحتاجه فقط.

الوحدة ملف JavaScript عادي، له ميزتان:

  1. ما بداخله خاص به. المتغيرات والدوال لا تتسرب إلى الملفات الأخرى، فلا يتصادم اسمان متشابهان في ملفين.
  2. يختار ما يصدّره (export) للآخرين، وما يستورده (import) منهم.

تخيّل مطبخاً منظماً: درج للسكاكين، ودرج للملاعق، ورف للتوابل. عندما تطبخ تفتح الدرج الذي تحتاجه وتأخذ منه الأداة المطلوبة فقط. ولو رُميت كل الأدوات في صندوق واحد لضاع وقتك في البحث.

ضع كلمة export قبل أي دالة أو متغير تريد أن تراه الملفات الأخرى:

math.js
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export function circleArea(radius) {
return roundTwo(PI * radius * radius);
}
function roundTwo(number) {
return Math.round(number * 100) / 100;
}

الدالة roundTwo بلا export، فهي أداة داخلية لا يراها أحد خارج هذا الملف.

في ملف آخر، اطلب ما تحتاجه بالاسم بين قوسين معقوفين:

main.js
import { add, circleArea } from "./math.js";
console.log(add(2, 3));
console.log(circleArea(10));
الناتج
5
314.16
  • الأسماء بين القوسين يجب أن تطابق الأسماء المصدَّرة تماماً.
  • المسار يبدأ بـ ./ ومعناها «في المجلد نفسه»، وينتهي بامتداد الملف .js.
  • أسطر import تُكتب في أعلى الملف.

ولو حاولت استيراد roundTwo لظهر خطأ، لأن الملف لم يصدّرها.

في HTML أضف type="module" إلى وسم script، واربط الملف الرئيسي فقط:

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

المتصفح يقرأ أسطر import في main.js ويحمّل باقي الملفات بنفسه. ووسم الوحدة مؤجَّل تلقائياً كأنك كتبت defer، فيُنفَّذ بعد أن تجهز عناصر الصفحة.

إعادة التسمية واستيراد الكل

Section titled “إعادة التسمية واستيراد الكل”

إذا تعارض اسم مستورد مع اسم عندك، غيّره بكلمة as:

main.js
import { add as sum } from "./math.js";
console.log(sum(10, 5));
الناتج
15

ويمكنك أن تستورد كل ما يصدّره الملف في كائن واحد:

main.js
import * as math from "./math.js";
console.log(math.PI);
console.log(math.add(1, 2));
الناتج
3.14159
3

التصدير الافتراضي: default

Section titled “التصدير الافتراضي: default”

إذا كان الملف يقدّم شيئاً رئيسياً واحداً، يمكنه أن يصدّره كتصدير افتراضي:

greet.js
export default function greet(name) {
return `أهلاً يا ${name}`;
}

وعند الاستيراد تكتب الاسم بدون قوسين معقوفين، وتختار له أي اسم تريده:

main.js
import greet from "./greet.js";
console.log(greet("مريم"));
الناتج
أهلاً يا مريم
التصدير بالاسم التصدير الافتراضي
الكتابة export function add export default function greet
الاستيراد import { add } بقوسين import greet بدون قوسين
العدد في الملف أي عدد واحد فقط

مثال كامل: سلة مشتريات في ثلاثة ملفات

Section titled “مثال كامل: سلة مشتريات في ثلاثة ملفات”
shop/
├─ index.html
├─ main.js
├─ cart.js
└─ format.js

ملف صغير لتنسيق الأسعار:

format.js
export function formatPrice(amount) {
return `${amount.toFixed(2)} جنيه`;
}

وملف السلة يستورد منه، ويصدّر دواله:

cart.js
import { formatPrice } from "./format.js";
const items = [];
export function addItem(name, price) {
items.push({ name, price });
}
export function getCount() {
return items.length;
}
export function getTotal() {
const total = items.reduce((sum, item) => sum + item.price, 0);
return formatPrice(total);
}

والملف الرئيسي يستخدم السلة:

main.js
import { addItem, getCount, getTotal } from "./cart.js";
addItem("قلم", 15);
addItem("دفتر", 40.5);
console.log("عدد المنتجات:", getCount());
console.log("الإجمالي:", getTotal());
الناتج
عدد المنتجات: 2
الإجمالي: 55.50 جنيه

لاحظ أن المصفوفة items بلا export. الملف الرئيسي لا يستطيع أن يلمسها مباشرة، ولا يغيّرها إلا عبر الدوال التي سمحنا بها. وهذه نفس فكرة الخصائص الخاصة في درس الكلاسات، لكن على مستوى الملف.

ولاحظ أيضاً أن main.js لا يعرف شيئاً عن format.js. كل ملف يستورد ما يحتاجه هو فقط.

هذا الدرس يحتاج عدة ملفات، فطبّقه على جهازك:

  1. أنشئ مجلداً باسم shop وفيه الملفات الثلاثة السابقة.
  2. أضف ملف index.html فيه السطر <script type="module" src="main.js"></script>.
  3. شغّل الصفحة بـ Live Server وافتح Console. يجب أن ترى:
الناتج المتوقع
عدد المنتجات: 2
الإجمالي: 55.50 جنيه
  1. أضف إلى cart.js دالة removeItem(name) وصدّرها، ثم استوردها في main.js واحذف القلم. يجب أن يصبح الإجمالي 40.50 جنيه.
  • نسيان type="module": يظهر الخطأ Cannot use import statement outside a module.
  • نسيان ./ أو الامتداد: كتابة "math" أو "./math" لا تعمل في المتصفح. اكتب المسار كاملاً: "./math.js".
  • الخلط بين النوعين: استيراد تصدير افتراضي بقوسين، أو تصدير بالاسم بدون قوسين. راجع طريقة التصدير في الملف الآخر.
  • فتح الصفحة بالنقر المزدوج: الوحدات لا تُحمَّل بدون خادم محلي.

سؤال

في الملف tools.js كتبنا export function sayHi(). ما سطر الاستيراد الصحيح؟

سؤال

دالة داخل وحدة لم نكتب قبلها export. من يستطيع استدعاءها؟

  • الوحدة ملف له نطاقه الخاص، يصدّر ما يريد ويستورد ما يحتاج.
  • export قبل الدالة أو المتغير، و import { الاسم } from "./file.js" لاستيراده.
  • export default لشيء رئيسي واحد، ويُستورد بدون قوسين معقوفين.
  • اربط الملف الرئيسي بـ <script type="module">، وشغّل الصفحة من خادم محلي.
  • قسّم مشروعك إلى ملفات صغيرة، كل ملف له مسؤولية واحدة واضحة.