
دليل عملي باللغة العربية يشرح 15 ميزة حديثة في JavaScript مع أمثلة قابلة للتنفيذ ونصائح عملية للمطورين المحترفين.
معرفة بناء جملة JavaScript لا تعني بالضرورة كتابة JavaScript يمكن للفريق صيانته بأمان. الكود الاحترافي أسهل قراءة، وأصعب إساءة استخدام، وأكثر وضوحًا في التعامل مع الأخطاء والإلغاء وشكل البيانات والأداء.
يشرح هذا الدليل 15 ميزة ونمطًا حديثًا يستخدمها المطورون المحترفون في التطبيقات الحقيقية. الهدف ليس استخدام الصياغة الذكية في كل مكان، بل اختيار الأدوات التي تقلل الغموض وتجعل الكود أسهل للمراجعة والتغيير.
تسمح ?. بالوصول الآمن إلى الخصائص عندما تكون القيمة null أو undefined. أما ?? فتضع قيمة افتراضية عند غياب القيمة فقط.
function getCustomerLabel(order) {
const name = order.customer?.profile?.displayName ?? 'Guest';
const points = order.customer?.loyaltyPoints ?? 0;
return `${name} (${points} points)`;
}
استخدم ?? بدل || عندما تكون 0 أو false أو النص الفارغ قيمًا صحيحة. ولا تستخدم ?. لإخفاء حالة غير متوقعة يضمنها نظامك، فقد يكون ظهور الخطأ أفضل.
يوضح التفكيك شكل البيانات التي تتوقعها الدالة، ويضع القيم الافتراضية قرب حدود الدالة.
function createAccount({ email, role = 'member', notifications = true }) {
if (!email) throw new Error('email is required');
return { email, role, notifications };
}
يمكنك أيضًا إعادة تسمية حقول API غير الواضحة، مثل created_at: createdAt. خذ الحقول التي تحتاج إليها فقط؛ كثرة المعاملات قد تعني أن الدالة تحتاج مسؤولية أصغر.
تجعل async وawait سير العمل غير المتزامن مقروءًا من الأعلى إلى الأسفل، لكن الكود الجيد يحدد المكان الذي يجب فيه التعامل مع الخطأ.
async function loadDashboard(userId) {
const response = await fetch(`/api/users/${userId}/dashboard`);
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
return response.json();
}
لا تلتقط الخطأ ثم تعيد undefined بلا سبب؛ فهذا يحول فشلًا واضحًا إلى مشكلة غامضة لاحقًا.
إذا كانت الطلبات مستقلة، شغّلها بالتوازي. أما إذا كان أحدها يعتمد على نتيجة الآخر، فاستخدم await بالتسلسل.
const [profile, projects, alerts] = await Promise.all([
fetchProfile(userId),
fetchProjects(userId),
fetchAlerts(userId),
]);
استخدم Promise.allSettled() عندما تريد معرفة نتيجة كل مهمة حتى لو فشلت إحداها. لا تنشئ آلاف الوعود دفعة واحدة؛ استخدم طابورًا أو محددًا لعدد المهام المتزامنة.
تلغي AbortController الطلبات القديمة عندما يبدأ المستخدم بحثًا جديدًا أو يغادر الصفحة.
const controller = new AbortController();
const response = await fetch('/api/products?q=rust', {
signal: controller.signal,
});
controller.abort();
ميّز الإلغاء المتوقع عن الخطأ الحقيقي حتى لا تمتلئ أدوات المراقبة بأخطاء غير مهمة.
const nextUser = {
...user,
preferences: { ...user.preferences, theme: 'dark' },
};
النسخ باستخدام spread سطحي، لذلك قد تبقى الكائنات المتداخلة مشتركة. استخدم structuredClone() عندما تحتاج نسخًا عميقًا لبيانات قابلة للهيكلة، مع العلم أنه لا ينسخ الدوال أو عقد DOM.
استخدم Set للقيم الفريدة وMap عندما تكون المفاتيح ديناميكية أو ليست نصوصًا فقط.
const uniqueTags = [...new Set(['js', 'api', 'js'])];
const counts = new Map();
counts.set('javascript', (counts.get('javascript') ?? 0) + 1);
هذا أوضح وأكثر أمانًا من الاعتماد على خصائص كائن عادي قد تتعارض مع الخصائص الموروثة.
استخدم map() للتحويل، وfilter() للاختيار، وfind() لأول نتيجة، وsome() للسؤال عن وجود تطابق، وevery() للتأكد من تطابق الجميع. لا تحول كل حل إلى reduce()؛ أحيانًا تكون حلقة for...of أوضح، خاصة مع الإيقاف المبكر أو العمل غير المتزامن.
const activeEmails = users
.filter((user) => user.isActive)
.map((user) => user.email);
في البيئات التي تدعمها، تجعل Object.groupBy() التجميع أكثر وضوحًا من reducer طويل.
const ticketsByStatus = Object.groupBy(tickets, (ticket) => ticket.status);
تحقق من إصدارات المتصفحات وNode.js قبل استعمال المزايا الجديدة؛ القرار الاحترافي يراعي بيئة التشغيل.
تستخدم الحقول التي تبدأ بـ# خصوصية تفرضها اللغة نفسها.
class RateLimiter {
#requests = 0;
constructor(limit) { this.limit = limit; }
tryConsume() {
if (this.#requests >= this.limit) return false;
this.#requests += 1;
return true;
}
}
الخصوصية تحمي الحالة الداخلية، لكنها لا تعالج صنفًا يملك مسؤوليات كثيرة جدًا.
توضح ES Modules الاعتماديات عبر import وexport. أما import() الديناميكي فيحمل الكود عند الحاجة فقط.
async function openChart(data) {
const { renderChart } = await import('./chart.js');
return renderChart(data);
}
هذا مفيد للمحررات والرسوم والأدوات الإدارية التي لا يحتاجها كل زائر عند بدء التطبيق.
استخدم Intl للتواريخ والأرقام والعملات والقوائم بدل تركيب النصوص يدويًا.
const price = new Intl.NumberFormat('ar-JO', {
style: 'currency', currency: 'JOD',
}).format(1299.5);
تقلل هذه الواجهات أخطاء اللغة واتجاه النص والعملة.
لا تبنِ عناوين URL بضم النصوص، لأن المسافات وعلامات & والمحارف العربية قد تكسر الرابط.
const url = new URL('/api/articles', window.location.origin);
url.searchParams.set('language', 'ar');
url.searchParams.set('query', 'async JavaScript');
fetch(url);
تساعد الأخطاء المخصصة المستهلك على التمييز بين التحقق والصلاحيات والشبكة وأخطاء المجال.
class ValidationError extends Error {
constructor(message, details = {}) {
super(message);
this.name = 'ValidationError';
this.details = details;
}
}
لا تضع كلمات المرور أو الرموز السرية أو البيانات الشخصية داخل رسائل الأخطاء أو السجلات.
تحتفظ الدالة المغلقة بالوصول إلى متغيراتها دون كشفها عالميًا.
function createIdGenerator(prefix = 'item') {
let current = 0;
return () => `${prefix}-${++current}`;
}
تستخدم closures في المصانع وmemoization وcallbacks، لكن لا تلتقط كائنات كبيرة بلا حاجة في مستمعات طويلة العمر.
يجمع المثال التالي التحقق، وترميز URL، والإلغاء، والأخطاء HTTP، والنتيجة المتوقعة:
async function findUsers({ query, page = 1, signal } = {}) {
const normalizedQuery = query?.trim();
if (!normalizedQuery) throw new ValidationError('البحث مطلوب');
const url = new URL('/api/users', window.location.origin);
url.searchParams.set('q', normalizedQuery);
url.searchParams.set('page', String(page));
const response = await fetch(url, { signal });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const payload = await response.json();
return {
users: payload.data ?? [],
total: payload.meta?.total ?? 0,
};
}
المستوى الاحترافي هنا ليس عدد المزايا، بل القرارات: تحقق مبكر، وعنوان URL آمن، وإلغاء، ورفض للاستجابات الفاشلة، ونتيجة ثابتة.
Promise.all().JavaScript الاحترافي لا يتعلق بعرض عدد المزايا التي تعرفها. يتعلق بجعل السلوك واضحًا، والحفاظ على القيم الصحيحة، واختيار بنية البيانات المناسبة، ومعالجة الفشل عمدًا، واحترام قيود بيئة التشغيل.
ابدأ بالميزات التي تزيل أكبر قدر من الغموض من كودك الحالي، ثم راجع تأثيرها على الاختبارات والأداء وقابلية الصيانة.
لا توجد تعليقات معتمدة بعد. قد تنتظر الردود الجديدة المراجعة.