مفاهيم أساسية في JavaScript
لا تنتقل إلى React أو Vue قبل إتقان هذه القواعد. دليل تفصيلي معمق يجعلك مطور ويب بمواصفات عالمية.
لماذا تفشل في تعلم React؟
الخطأ الذي يقع فيه 90% من المبتدئين هو القفز مباشرة إلى أطر العمل (Frameworks) بمجرد معرفة أساسيات المتغيرات والشروط. عندما تواجه كوداً في React وتجده معقداً، فالمشكلة في الغالب ليست في React، بل في جهلك بميزات JavaScript الحديثة (ES6+).
في هذا الدليل الحصري من كوداتي، سنغوص بعمق في أهم 7 مفاهيم نستخدمها يومياً كمطورين محترفين، مع شرح شامل للفرق بين الماضي والحاضر.

1. الدوال السهمية (Arrow Functions)
قد تظن أن Arrow Functions هي مجرد طريقة "أقصر" لكتابة الدوال، لكن هذا الفهم سطحي جداً. الفرق الجوهري يكمن في كيفية تعاملها مع الكلمة المفتاحية this.
في الدوال التقليدية function()، قيمة this تتغير بناءً على "من" قام باستدعاء الدالة (سياق الاستدعاء). أما في الدوال السهمية، فإنها لا تمتلك this خاصة بها، بل ترثها من النطاق الخارجي (Lexical Scope). هذا يحل واحدة من أكبر مشاكل الجافا سكريبت القديمة، خاصة عند تمرير الدوال كـ Callbacks داخل دوال أخرى (مثل setTimeout).
this وتسبب خطأ، بينما تحلها الطريقة الحديثة (✅) بشكل سليم ومختصر.
// ❌ الطريقة القديمة (مشكلة this)
const user = {
name: "كوداتي",
sayHi: function() {
setTimeout(function() {
// هنا ستكون this.name غير معرفة (undefined)
// لأن الدالة الداخلية فقدت سياق الكائن user
console.log("مرحباً " + this.name);
}, 1000);
}
};
// ✅ الطريقة الحديثة (Arrow Function تحل المشكلة)
const userPro = {
name: "كوداتي",
sayHi: function() {
setTimeout(() => {
// الدالة السهمية ترث this من دالة sayHi بنجاح
console.log(`مرحباً ${this.name}`);
}, 1000);
}
};
// اختصار كود المكونات في React
const Button = (props) => <button>{props.text}</button>;
2. نصوص القوالب (Template Literals)
في الماضي، كان دمج المتغيرات مع النصوص (String Concatenation) باستخدام علامة + كابوساً، خصوصاً عند كتابة أكواد HTML داخل الجافا سكريبت، حيث كان يتعين عليك الانتباه للمسافات وعلامات التنصيص المفردة والمزدوجة.
نصوص القوالب تستخدم علامة الباك تيك ` (الموجودة تحت زر Esc)، وتسمح لك بأمرين عظيمين: أولاً، حقن المتغيرات والعمليات الحسابية مباشرة داخل النص باستخدام ${}. ثانياً، دعم الأسطر المتعددة (Multi-line Strings) بدون الحاجة لكتابة \n.
const courseName = "React.js";
const price = 50;
const discount = 10;
// ❌ الطريقة القديمة المزعجة والمقروئية السيئة
const oldMessage = "الكورس: " + courseName + "\nالسعر بعد الخصم: " + (price - discount) + "$";
// ✅ الطريقة الحديثة (Template Literals)
const newMessage = `
الكورس: ${courseName}
السعر بعد الخصم: ${price - discount}$
`;
// مفيدة جداً عند بناء واجهات ديناميكية (HTML)
const createCard = (title, body) => `
<div class="card">
<h2>${title.toUpperCase()}</h2>
<p>${body}</p>
</div>
`;
3. تفكيك البيانات (Destructuring Assignment)
يُعد هذا المفهوم العمود الفقري لبرمجة الواجهات الحديثة. Destructuring يسمح لك باستخراج خصائص محددة من كائن (Object) أو عناصر من مصفوفة (Array) وتخزينها في متغيرات منفصلة بأسطر قليلة جداً وبكود نظيف.
بدون هذا المفهوم، ستضطر في React مثلاً إلى كتابة props.user.name في كل مرة تريد فيها عرض الاسم. مع التفكيك، يمكنك استخراج name فوراً، بل ويمكنك إعطاء قيم افتراضية (Default Values) في حال كانت البيانات غير موجودة، أو إعادة تسمية المتغير لتجنب التعارض.
const developer = {
name: "أحمد",
skills: ["HTML", "CSS", "JS"],
social: { twitter: "@ahmed_dev" }
};
// ❌ الطريقة القديمة
const oldName = developer.name;
const oldTwitter = developer.social.twitter;
// ✅ الطريقة الحديثة (تفكيك كائن متداخل مع قيم افتراضية)
const {
name,
social: { twitter },
role = "مطور واجهات" // قيمة افتراضية لأن role غير موجود
} = developer;
console.log(name, twitter, role); // "أحمد" "@ahmed_dev" "مطور واجهات"
// 💡 استخدامها القوي في React لاستلام الـ Props
const UserProfile = ({ name, role = "عضو" }) => {
return <div>الاسم: {name} | الرتبة: {role}</div>;
};
// 📦 تفكيك المصفوفات (مهم جداً في React useState)
const colors = ["أحمر", "أخضر", "أزرق"];
const [firstColor, secondColor] = colors; // firstColor = "أحمر"
4. معاملات التمدد والتجميع (Spread & Rest `...`)
الثلاث نقاط ... لها سحر خاص في جافا سكريبت، ويختلف عملها بناءً على مكان استخدامها.
1. التمدد (Spread): يُستخدم لنشر أو "تفريغ" محتويات مصفوفة أو كائن داخل مصفوفة أو كائن آخر. هذه هي الطريقة الآمنة لنسخ البيانات (Shallow Copy) بدلاً من الإشارة لنفس المرجع في الذاكرة (Reference)، وهو شرط أساسي لتحديث الحالة (State) في React.
2. التجميع (Rest): يُستخدم في إعدادات الدوال لجمع عدد غير محدود من المُعاملات (Arguments) ووضعها في مصفوفة واحدة.
... (✅) بنسخ ودمج المصفوفات والكائنات بأمان وسهولة.
// --- أولاً: Spread Operator (التمدد والنسخ) ---
const arr1 = [1, 2, 3];
const arr2 = [4, 5];
// ❌ الطريقة القديمة (معقدة)
// const combinedArray = arr1.concat(arr2).concat([6]);
// ✅ الطريقة الحديثة (دمج مصفوفتين بسهولة)
const combinedArray = [...arr1, ...arr2, 6]; // [1, 2, 3, 4, 5, 6]
// ✅ تحديث كائن دون تدمير البيانات القديمة (أساسيات React State)
const userSettings = { theme: "dark", notifications: true };
const newSettings = { ...userSettings, theme: "light", language: "ar" };
// { theme: "light", notifications: true, language: "ar" }
// --- ثانياً: Rest Operator (تجميع الباقي) ---
// ✅ تخيل دالة تجمع أي عدد من الأرقام
const sumAll = (...numbers) => {
return numbers.reduce((total, num) => total + num, 0);
};
console.log(sumAll(10, 20, 30, 40)); // 100
// ✅ استخراج الباقي عند التفكيك
const [first, ...others] = ["تفاحة", "موز", "برتقال"];
console.log(others); // ["موز", "برتقال"]
5. دوال المصفوفات المتقدمة (Map, Filter, Reduce)
كمطور حديث، يجب أن تتوقف فوراً عن استخدام حلقة for التقليدية لتعديل البيانات. البرمجة الوظيفية (Functional Programming) هي المعيار الآن.
.map(): تمر على كل عنصر، تنفذ عليه عملية، وتُرجع مصفوفة جديدة تماماً بنفس الطول. (تُستخدم لطباعة عناصر HTML في React)..filter(): تُرجع مصفوفة جديدة تحتوي فقط على العناصر التي تحقق شرطاً معيناً (تُستخدم لعمليات البحث والحذف)..reduce(): أداة قوية لتقليص المصفوفة إلى قيمة واحدة (مثل حساب المجموع الكلي لسلة المشتريات).
for التقليدية والطويلة (❌)، واستخدم دوال المصفوفات الحديثة (✅) لكتابة كود نظيف ومقروء من سطر واحد.
const products = [
{ id: 1, name: "لابتوب", price: 1000 },
{ id: 2, name: "هاتف", price: 500 },
{ id: 3, name: "سماعات", price: 100 }
];
// ❌ الطريقة القديمة باستخدام for (طويلة وتأخذ مساحة)
/*
const productNames = [];
for (let i = 0; i < products.length; i++) {
productNames.push(products[i].name);
}
*/
// ✅ 1. استخدام Map للحصول على مصفوفة بأسماء المنتجات فقط
const productNames = products.map(p => p.name);
// ["لابتوب", "هاتف", "سماعات"]
// ✅ 2. استخدام Filter لإيجاد المنتجات الأرخص من 600
const cheapProducts = products.filter(p => p.price < 600);
// [{name: "هاتف"...}, {name: "سماعات"...}]
// ✅ 3. استخدام Reduce لحساب إجمالي الأسعار
const totalCost = products.reduce((total, p) => total + p.price, 0);
// 1600
// 💡 دمجهم معاً (Chaining) - أسلوب المحترفين
const expensiveNames = products
.filter(p => p.price >= 500)
.map(p => p.name);
// ["لابتوب", "هاتف"]
6. البرمجة غير المتزامنة (Async/Await & Fetch)
الويب يعتمد على جلب البيانات من الخوادم (APIs). هذه العملية تأخذ وقتاً (أجزاء من الثانية إلى عدة ثوانٍ). إذا توقفت جافا سكريبت لانتظار البيانات، سيتجمد الموقع بالكامل!
لحل ذلك، نستخدم الوعود (Promises). قديماً كنا نستخدم .then() للتعامل مع النتيجة عند وصولها، ولكن هذا كان يؤدي إلى كود متداخل ومعقد. الآن، نستخدم async و await لجعل الكود غير المتزامن يُقرأ وكأنه كود متزامن تسلسلي، مما يسهل اكتشاف الأخطاء باستخدام try...catch.
.then() المتكررة (❌)، وشاهد كيف تجعل async/await (✅) الكود يُقرأ بتسلسل منطقي ومريح للعين.
// ❌ الطريقة القديمة (تسبب تداخل الكود - Callback Hell)
/*
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
*/
// ✅ الطريقة الحديثة (تسلسلية ومريحة للقراءة)
const fetchUsers = async () => {
try {
// await توقف تنفيذ هذا السطر فقط حتى تصل الاستجابة
const response = await fetch('https://jsonplaceholder.typicode.com/users');
// التحقق من نجاح الطلب
if (!response.ok) throw new Error("حدث خطأ في الشبكة");
// تحويل البيانات إلى JSON
const data = await response.json();
console.log("تم جلب البيانات بنجاح:", data);
} catch (error) {
// التقاط أي خطأ (مثلاً انقطاع الإنترنت)
console.error("فشل جلب البيانات:", error.message);
}
};
fetchUsers();
7. نظام الوحدات (ES Modules - Import/Export)
لا يمكنك بناء تطبيق ضخم بكتابة آلاف الأسطر في ملف script.js واحد. هندسة البرمجيات الحديثة تتطلب تقسيم الكود إلى "وحدات" (Modules) صغيرة قابلة لإعادة الاستخدام والصيانة.
يتيح لك export تصدير دالة أو متغير من ملف، ويتيح لك import استدعاءه في ملف آخر. يجب أن تفهم الفرق بين التصدير الافتراضي (Default Export) (يسمح بتصدير شيء واحد رئيسي من الملف) و التصدير المسمى (Named Export) (يسمح بتصدير عدة أشياء ويجب استيرادها بنفس الاسم داخل أقواس `{}`).
// ❌ قديماً: وضع آلاف الأسطر في ملف script.js واحد.
// ✅ حديثاً: تقسيم الكود لملفات قابلة لإعادة الاستخدام.
// --- ملف utils.js (الذي يحتوي على الأدوات) ---
// Named Export (تصدير مسمى - يمكن تصدير عدة دوال)
export const formatDate = (date) => new Intl.DateTimeFormat('ar').format(date);
export const calculateTax = (price) => price * 0.15;
// Default Export (تصدير افتراضي - شيء واحد فقط للملف)
const mainFunction = () => console.log("الدالة الرئيسية");
export default mainFunction;
// --- ملف app.js (الملف الرئيسي الذي يستقبل الأكواد) ---
// استيراد التصدير الافتراضي (يمكنك تسميته أي اسم تريده)
import myMainFunc from './utils.js';
// استيراد التصدير المسمى (يجب استخدام نفس الاسم والأقواس)
import { formatDate, calculateTax } from './utils.js';
myMainFunc();
console.log(calculateTax(100)); // 15
7 أسئلة شائعة عن احتراف الجافا سكريبت
document.getElementById). يجب أن تتعلمه بعد إتقان الأساسيات وقبل الانتقال إلى React، لأنه سيعطيك فهماً عميقاً لكيفية عمل المتصفح.var لأنها تسبب مشاكل في نطاق الوصول (Scope). استخدم const دائماً لتعريف المتغيرات التي لن تتغير قيمتها (وهي المفضلة)، واستخدم let فقط للقيم التي تحتاج إلى إعادة تعيينها لاحقاً (مثل العدادات).مبروك! لقد أتممت المرحلة التأسيسية
الآن، أنت لست مجرد مبتدئ ينسخ الأكواد. أنت تفهم **المنطق (Logic)** وكيف تتحدث لغة الجافا سكريبت الحديثة. بانتهاء هذا المقال، أصبحت تملك خارطة طريق واضحة، أتقنت الواجهات، وحصلت على أدوات جاهزة، وتسلحت بأساسيات البرمجة.