الرئيسية التوثيق

مقدمة في جافا سكريبت

ES2023 آخر تحديث: 21/04/2025

جافا سكريبت (JavaScript) هي لغة برمجة عالية المستوى، مفسرة، وكائنية التوجه. تُستخدم بشكل أساسي لتطوير صفحات الويب التفاعلية وتطبيقات الويب. جافا سكريبت هي اللغة البرمجية الأساسية للويب، حيث تُستخدم من قبل أكثر من 97% من مواقع الإنترنت.

تاريخ جافا سكريبت

تم تطوير جافا سكريبت في عام 1995 بواسطة Brendan Eich أثناء عمله في شركة Netscape. في البداية، كانت تُسمى "Mocha"، ثم "LiveScript"، وأخيرًا "JavaScript". على الرغم من اسمها، إلا أن JavaScript لا علاقة لها بلغة Java البرمجية.

أهمية جافا سكريبت

تُعد جافا سكريبت من أهم لغات البرمجة في الوقت الحالي للأسباب التالية:

  • تعمل على جانب العميل (Client-side) وجانب الخادم (Server-side) مع Node.js
  • تمتاز بالمرونة وسهولة التعلم للمبتدئين
  • تدعم نموذج البرمجة الوظيفية والكائنية
  • بيئة عمل غنية ومجتمع كبير من المطورين

كيف تعمل جافا سكريبت؟

تعمل جافا سكريبت كلغة برمجة مفسرة في المتصفح. عندما يقوم المستخدم بتحميل صفحة ويب، يقوم المتصفح بقراءة كود HTML و CSS أولاً، ثم تنفيذ كود جافا سكريبت. يمكن لجافا سكريبت تعديل محتوى الصفحة وأنماطها والتفاعل مع المستخدم.

مثال بسيط على كود جافا سكريبت

// إنشاء متغير وإسناد قيمة له
let name = "Ahmed";

// إنشاء دالة للترحيب
function greet(name) {
  return `Hello, ${name}!`;
}

// استدعاء الدالة
let message = greet(name);

// طباعة النتيجة في وحدة التحكم
console.log(message);

// النتيجة: Hello, Ahmed!

صياغة اللغة وبنيتها

صياغة جافا سكريبت متأثرة بلغات مثل C و Java. هناك بعض القواعد الأساسية التي يجب معرفتها:

  • جافا سكريبت حساسة لحالة الأحرف (case-sensitive)، أي أن المتغير "name" يختلف عن "Name"
  • تنتهي التعليمات (statements) بفاصلة منقوطة (;) اختيارياً في ES6 وما بعدها
  • يتم تجاهل المسافات البيضاء (white space) خارج النصوص

مثال على صياغة جافا سكريبت

// الترميز الأساسي لجافا سكريبت
let x = 5;          // تعريف متغير
let y = 6;          // تعريف متغير آخر
let z = x + y;      // حساب المجموع

// كتابة الكود في أكثر من سطر
document.getElementById("demo").innerHTML = 
"The sum is: " + z;

التعليقات في جافا سكريبت

التعليقات مهمة في أي لغة برمجة لتوثيق الكود وشرح طريقة عمله. في جافا سكريبت، هناك نوعان من التعليقات:

أنواع التعليقات في جافا سكريبت

// هذا تعليق في سطر واحد

/* 
   هذا تعليق متعدد الأسطر
   يمكن أن يمتد على عدة أسطر
*/

let value = 42; // يمكن وضع تعليق بعد الكود أيضاً

// التعليقات لا يتم تنفيذها، ويمكن استخدامها لإلغاء تنفيذ كود معين
// console.log("This will not be executed");

المتغيرات في جافا سكريبت

يتم استخدام المتغيرات لتخزين البيانات في الذاكرة. في جافا سكريبت الحديثة، هناك ثلاث طرق لتعريف المتغيرات:

var

الطريقة التقليدية لتعريف المتغيرات، تكون متاحة في نطاق الدالة.

let

تعريف متغير متاح فقط في نطاق الكتلة البرمجية، يمكن تغيير قيمته.

const

لتعريف ثابت لا يمكن تغيير قيمته بعد التعريف.

مثال على استخدام المتغيرات

// استخدام var (نطاق الدالة)
var name1 = "Mohammed";
function test() {
  var x = 10;  // متاح فقط داخل الدالة
}

// استخدام let (نطاق الكتلة البرمجية)
let name2 = "Ahmed";
{
  let y = 20;  // متاح فقط داخل هذه الكتلة
}

// استخدام const (متغير ثابت)
const PI = 3.14159;
// PI = 3.14;  // سيؤدي هذا إلى خطأ

// الفرق بين var و let في النطاق
function scopeExample() {
  if (true) {
    var varVariable = "I am var";
    let letVariable = "I am let";
  }
  console.log(varVariable);  // يعمل بشكل طبيعي
  // console.log(letVariable);  // خطأ: letVariable غير معرّف
}

أنواع البيانات الأساسية

جافا سكريبت هي لغة ذات أنواع ديناميكية، مما يعني أن نوع المتغير يمكن أن يتغير أثناء تنفيذ البرنامج. أنواع البيانات الأساسية في جافا سكريبت هي:

النوع الوصف مثال
String سلسلة من الأحرف "Hello"، 'Hi'، `World`
Number قيم رقمية صحيحة أو عشرية 42، 3.14، -7
BigInt أرقام كبيرة جداً 9007199254740991n
Boolean قيمة منطقية true، false
Undefined متغير تم تعريفه ولكن لم يتم إسناد قيمة له undefined
Null قيمة فارغة متعمدة null
Symbol قيمة فريدة وغير متغيرة Symbol('id')
Object مجموعة من الخصائص والقيم {name: "Ahmed", age: 30}

مثال على استخدام أنواع البيانات المختلفة

// أمثلة على أنواع البيانات المختلفة
let text = "Hello World";            // نوع String
let number = 42;                     // نوع Number
let decimal = 3.14;                  // نوع Number (عشري)
let isActive = true;                 // نوع Boolean
let array = [1, 2, 3, "four"];       // نوع Array (وهو في الأساس نوع Object)
let person = {                       // نوع Object
  name: "Sara",
  age: 25,
  city: "Riyadh"
};
let notDefined;                      // نوع Undefined
let empty = null;                    // نوع Null
let id = Symbol("id");               // نوع Symbol
let bigNumber = 9007199254740991n;   // نوع BigInt

// التحقق من نوع البيانات
console.log(typeof text);       // "string"
console.log(typeof number);     // "number"
console.log(typeof isActive);   // "boolean"
console.log(typeof array);      // "object"
console.log(typeof person);     // "object"
console.log(typeof notDefined); // "undefined"
console.log(typeof empty);      // "object" (هذا خطأ في تصميم اللغة)
console.log(typeof id);         // "symbol"
console.log(typeof bigNumber);  // "bigint"

تحويل أنواع البيانات

في كثير من الأحيان، نحتاج إلى تحويل نوع بيانات إلى نوع آخر. يمكننا القيام بذلك بطريقتين:

  • التحويل الضمني: يقوم به جافا سكريبت تلقائياً عند الحاجة (مثل عند إجراء عمليات حسابية)
  • التحويل الصريح: يتم من خلال دوال مثل String(), Number(), Boolean() وغيرها

مثال على تحويل أنواع البيانات

// التحويل الصريح - تحويل إلى String
let value = 50;
let stringValue = String(value);  // تحويل الرقم إلى نص
console.log(stringValue);         // "50"
console.log(typeof stringValue);  // "string"

// طرق أخرى للتحويل إلى String
let anotherString = value.toString();
let templateString = `${value}`;

// التحويل الصريح - تحويل إلى Number
let strNum = "25";
let num = Number(strNum);         // تحويل النص إلى رقم
console.log(num);                 // 25
console.log(typeof num);          // "number"

// طرق أخرى للتحويل إلى Number
let intValue = parseInt("25.5");  // 25 (يأخذ الجزء الصحيح فقط)
let floatValue = parseFloat("25.5");  // 25.5
let unaryPlus = +"25";  // 25 (استخدام عامل الجمع الأحادي)

// التحويل الصريح - تحويل إلى Boolean
let zero = 0;
let boolValue = Boolean(zero);    // تحويل إلى قيمة منطقية
console.log(boolValue);           // false (الصفر يعتبر false)

// القيم التي تعتبر false عند تحويلها:
console.log(Boolean(0));          // false
console.log(Boolean(""));         // false
console.log(Boolean(null));       // false
console.log(Boolean(undefined));  // false
console.log(Boolean(NaN));        // false
console.log(Boolean(false));      // false

// كل القيم الأخرى تعتبر true
console.log(Boolean(1));          // true
console.log(Boolean("hello"));    // true
console.log(Boolean([]));         // true
console.log(Boolean({}));         // true

// التحويل الضمني
let result = "10" + 5;            // التحويل الضمني إلى نص
console.log(result);              // "105" (تم تحويل الرقم 5 إلى نص)

let mathResult = "10" - 5;        // التحويل الضمني إلى رقم
console.log(mathResult);          // 5 (تم تحويل النص "10" إلى رقم)

العمليات الحسابية

تستخدم العمليات الحسابية لإجراء العمليات الأساسية مثل الجمع والطرح والضرب والقسمة على الأرقام والمتغيرات.

العملية الرمز وصف مثال
الجمع + جمع الأرقام 5 + 2 = 7
الطرح - طرح الأرقام 5 - 2 = 3
الضرب * ضرب الأرقام 5 * 2 = 10
القسمة / قسمة الأرقام 5 / 2 = 2.5
باقي القسمة % باقي القسمة 5 % 2 = 1
زيادة بمقدار 1 ++ زيادة المتغير بمقدار 1 x++
نقصان بمقدار 1 -- إنقاص المتغير بمقدار 1 x--
أس (القوة) ** رفع رقم لقوة معينة 5 ** 2 = 25

مثال على العمليات الحسابية

// عمليات حسابية أساسية
let a = 10;
let b = 3;

let sum = a + b;         // الجمع: 13
let difference = a - b;  // الطرح: 7
let product = a * b;     // الضرب: 30
let quotient = a / b;    // القسمة: 3.33...
let remainder = a % b;   // باقي القسمة: 1
let power = a ** b;      // الأس: 10^3 = 1000

// عمليات الزيادة والنقصان
let x = 5;
x++;                    // زيادة بمقدار 1 (x الآن يساوي 6)
let y = x++;            // y = 6, ثم x يزداد إلى 7 (زيادة بعدية)
let z = ++x;            // x يزداد إلى 8, ثم z = 8 (زيادة قبلية)

// عمليات الإسناد المختصرة
let n = 10;
n += 5;                 // نفس n = n + 5 (n الآن يساوي 15)
n -= 3;                 // نفس n = n - 3 (n الآن يساوي 12)
n *= 2;                 // نفس n = n * 2 (n الآن يساوي 24)
n /= 4;                 // نفس n = n / 4 (n الآن يساوي 6)
n %= 4;                 // نفس n = n % 4 (n الآن يساوي 2)
n **= 3;                // نفس n = n ** 3 (n الآن يساوي 8)

// دوال رياضية مفيدة من كائن Math
console.log(Math.round(4.7));     // 5 (تقريب لأقرب عدد صحيح)
console.log(Math.ceil(4.1));      // 5 (تقريب لأعلى)
console.log(Math.floor(4.9));     // 4 (تقريب لأسفل)
console.log(Math.abs(-7));        // 7 (القيمة المطلقة)
console.log(Math.sqrt(16));       // 4 (الجذر التربيعي)
console.log(Math.min(2, 4, 1));   // 1 (أصغر قيمة)
console.log(Math.max(2, 4, 1));   // 4 (أكبر قيمة)
console.log(Math.random());       // رقم عشوائي بين 0 و 1

عمليات المقارنة

تستخدم عمليات المقارنة لمقارنة القيم وإرجاع قيمة منطقية (true أو false). هذه العمليات مهمة في التعبيرات الشرطية.

العملية الرمز وصف مثال
يساوي (قيمة) == مقارنة القيم مع تحويل النوع 5 == "5" (true)
يساوي تماماً (قيمة ونوع) === مقارنة القيم والنوع 5 === "5" (false)
لا يساوي != عدم المساواة مع تحويل النوع 5 != "6" (true)
لا يساوي تماماً !== عدم المساواة في القيمة أو النوع 5 !== "5" (true)
أكبر من > القيمة الأولى أكبر من الثانية 5 > 3 (true)
أصغر من < القيمة الأولى أصغر من الثانية 5 < 3 (false)
أكبر من أو يساوي >= القيمة الأولى أكبر من أو تساوي الثانية 5 >= 5 (true)
أصغر من أو يساوي <= القيمة الأولى أصغر من أو تساوي الثانية 5 <= 5 (true)

مثال على عمليات المقارنة

// أمثلة على عمليات المقارنة
let a = 5;
let b = "5";
let c = 10;

// عمليات المساواة
console.log(a == b);    // true (القيمة متساوية بعد التحويل)
console.log(a === b);   // false (النوع مختلف)
console.log(a != c);    // true (القيمة مختلفة)
console.log(a !== b);   // true (النوع مختلف)

// عمليات المقارنة
console.log(a > c);     // false (5 ليست أكبر من 10)
console.log(a < c);     // true (5 أصغر من 10)
console.log(a >= 5);    // true (5 تساوي 5)
console.log(c <= 10);   // true (10 تساوي 10)

// مقارنة السلاسل النصية (تتم حسب الترتيب الأبجدي)
console.log("apple" < "banana");  // true (a يأتي قبل b في الترتيب الأبجدي)
console.log("10" > "2");          // false (مقارنة نصية: "1" يأتي قبل "2")

// المقارنة بين أنواع مختلفة
console.log(null == undefined);   // true
console.log(null === undefined);  // false
console.log(0 == false);          // true (التحويل الضمني)
console.log(0 === false);         // false (أنواع مختلفة)
console.log("" == false);         // true (التحويل الضمني)
console.log(NaN == NaN);          // false (NaN لا يساوي أي شيء، حتى نفسه)
console.log(NaN === NaN);         // false

العمليات المنطقية

تستخدم العمليات المنطقية لتقييم عدة شروط ودمجها. هناك ثلاث عمليات منطقية أساسية في جافا سكريبت:

العملية الرمز وصف مثال
و (AND) && يرجع true إذا كانت جميع الشروط true x > 0 && x < 10
أو (OR) || يرجع true إذا كان أحد الشروط على الأقل true x < 0 || x > 10
ليس (NOT) ! عكس القيمة المنطقية !isActive

مثال على العمليات المنطقية

// أمثلة على العمليات المنطقية
let x = 7;
let isActive = true;
let isAdmin = false;

// عملية AND (&&)
let inRange = x > 0 && x < 10;  // true (لأن كلا الشرطين صحيحان)
console.log(inRange);           // true

// عملية OR (||)
let outOfRange = x <= 0 || x >= 10;  // false (لأن كلا الشرطين خاطئان)
console.log(outOfRange);             // false

// عملية NOT (!)
let notActive = !isActive;  // عكس قيمة isActive
console.log(notActive);     // false

// دمج العمليات المنطقية
let canAccess = isActive && (isAdmin || x > 5);  // true
console.log(canAccess);

// تقييم الدارة القصيرة (Short-circuit evaluation)
// في عملية AND، إذا كان الشرط الأول false، لن يتم تقييم الشرط الثاني
// في عملية OR، إذا كان الشرط الأول true، لن يتم تقييم الشرط الثاني
let result1 = false && console.log("This won't be executed");  // لن يتم تنفيذ console.log
let result2 = true || console.log("This won't be executed");   // لن يتم تنفيذ console.log

// استخدام العمليات المنطقية كبدائل للشروط
// باستخدام تقييم الدارة القصيرة لـ && (إذا كان الأول true، يتم إرجاع الثاني)
let username = "user123";
let defaultName = "Guest";
let displayName = username && username.trim();  // إذا كان هناك username، استخدمه

// باستخدام تقييم الدارة القصيرة لـ || (إذا كان الأول false، يتم إرجاع الثاني)
let userInput = "";
let fallbackValue = "Default";
let result = userInput || fallbackValue;  // إذا كان المدخل فارغاً، استخدم القيمة الاحتياطية
console.log(result);  // "Default"

// استخدام المعامل ?? للقيم null وundefined فقط
let nullValue = null;
let undefinedValue;
let value1 = 0;
let value2 = "";
console.log(nullValue ?? "Fallback");      // "Fallback"
console.log(undefinedValue ?? "Fallback"); // "Fallback"
console.log(value1 ?? "Fallback");         // 0 (يحتفظ بالقيم "الفارغة" مثل 0 و "")
console.log(value2 ?? "Fallback");         // "" (نفس السبب)

عمليات السلاسل النصية

تعتبر السلاسل النصية (Strings) من أنواع البيانات الأساسية في جافا سكريبت، وهناك العديد من العمليات التي يمكن إجراؤها عليها.

مثال على عمليات السلاسل النصية

// إنشاء سلاسل نصية
let str1 = "Hello";
let str2 = 'World';
let str3 = `Hello World`;  // قوالب نصية (Template literals)

// دمج السلاسل النصية
let greeting = str1 + " " + str2;  // "Hello World"
let templateGreeting = `${str1} ${str2}`;  // "Hello World" باستخدام قوالب نصية

// خصائص وطرق السلاسل النصية
console.log(str1.length);  // 5 (طول النص)
console.log(str1[0]);      // "H" (الوصول إلى حرف بمؤشر معين)
console.log(str1.charAt(1));  // "e" (طريقة بديلة للوصول إلى حرف)

// طرق البحث
console.log(greeting.indexOf("World"));  // 6 (موقع بداية الكلمة)
console.log(greeting.includes("Hello")); // true (التحقق من وجود نص)
console.log(greeting.startsWith("Hello")); // true (التحقق من بداية النص)
console.log(greeting.endsWith("World"));   // true (التحقق من نهاية النص)

// طرق استخراج جزء من النص
console.log(greeting.slice(0, 5));     // "Hello" (من الموقع 0 وحتى 5 غير متضمن)
console.log(greeting.substring(6, 11)); // "World" (من الموقع 6 وحتى 11 غير متضمن)
console.log(greeting.substr(6, 5));     // "World" (من الموقع 6 وبطول 5 أحرف)

// طرق التعديل
console.log(greeting.toUpperCase());    // "HELLO WORLD" (تحويل إلى أحرف كبيرة)
console.log(greeting.toLowerCase());    // "hello world" (تحويل إلى أحرف صغيرة)
console.log(str1.concat(" ", str2));    // "Hello World" (دمج السلاسل)
console.log("  Hello  ".trim());        // "Hello" (إزالة المسافات في البداية والنهاية)

// طرق الاستبدال
console.log(greeting.replace("World", "JavaScript")); // "Hello JavaScript"
console.log("Hello World World".replace(/World/g, "JS")); // "Hello JS JS" (استبدال كل الحالات باستخدام التعبير النمطي)

// تقسيم النص إلى مصفوفة
console.log("apple,banana,orange".split(",")); // ["apple", "banana", "orange"]
console.log("Hello World".split(" "));         // ["Hello", "World"]
console.log("Hello".split(""));                // ["H", "e", "l", "l", "o"]

// قوالب نصية متعددة الأسطر
let multiLine = `
  This is line 1
  This is line 2
  This is line 3
`;

// قوالب نصية مع تعبيرات
let name = "John";
let age = 30;
let info = `My name is ${name} and I am ${age} years old.`;
console.log(info); // "My name is John and I am 30 years old."

// طرق أخرى مفيدة
console.log("Hello".repeat(3));          // "HelloHelloHello"
console.log("Hello".padStart(10, "*"));  // "*****Hello"
console.log("Hello".padEnd(10, "*"));    // "Hello*****"

التعبيرات الشرطية

التعبيرات الشرطية تسمح لك بتنفيذ أكواد مختلفة بناءً على شروط محددة. في جافا سكريبت، هناك عدة طرق لكتابة التعبيرات الشرطية.

عبارات if, else و else if

تُستخدم عبارات if و else لتنفيذ كود معين بناءً على شرط معين. يتم تنفيذ الكود داخل كتلة if إذا كان الشرط صحيحاً، وإلا يتم تنفيذ الكود داخل كتلة else (إن وجدت).

مثال على عبارات if, else, else if

// تعبير if بسيط
let age = 18;

if (age >= 18) {
  console.log("أنت بالغ");
}

// تعبير if-else
let time = 15;

if (time < 12) {
  console.log("صباح الخير");
} else {
  console.log("مساء الخير");
}

// تعبيرات if-else-if-else متعددة
let score = 85;

if (score >= 90) {
  console.log("ممتاز");
} else if (score >= 80) {
  console.log("جيد جداً");
} else if (score >= 70) {
  console.log("جيد");
} else if (score >= 60) {
  console.log("مقبول");
} else {
  console.log("راسب");
}

// تعبيرات if متداخلة
let num = 15;

if (num > 0) {
  console.log("الرقم موجب");
  
  if (num % 2 === 0) {
    console.log("والرقم زوجي");
  } else {
    console.log("والرقم فردي");
  }
} else if (num < 0) {
  console.log("الرقم سالب");
} else {
  console.log("الرقم هو صفر");
}

// العامل الثلاثي (Ternary Operator)
// condition ? expressionIfTrue : expressionIfFalse
let message = age >= 18 ? "أنت بالغ" : "أنت قاصر";
console.log(message);

// عوامل ثلاثية متداخلة
let greeting = time < 12 ? "صباح الخير" : time < 18 ? "مساء الخير" : "مساء الخير جداً";
console.log(greeting);

// تمديد على العامل الثلاثي (سلسلة منه)
let grade = 
  score >= 90 ? "ممتاز" :
  score >= 80 ? "جيد جداً" :
  score >= 70 ? "جيد" :
  score >= 60 ? "مقبول" :
  "راسب";

عبارة switch

تستخدم عبارة switch لتنفيذ كود مختلف بناءً على قيم مختلفة للمتغير. يمكن استخدامها كبديل لعبارات if-else-if المتعددة عندما يتم فحص نفس المتغير.

مثال على عبارة switch

// عبارة switch بسيطة
let day = 3;
let dayName;

switch (day) {
  case 1:
    dayName = "الأحد";
    break;
  case 2:
    dayName = "الإثنين";
    break;
  case 3:
    dayName = "الثلاثاء";
    break;
  case 4:
    dayName = "الأربعاء";
    break;
  case 5:
    dayName = "الخميس";
    break;
  case 6:
    dayName = "الجمعة";
    break;
  case 7:
    dayName = "السبت";
    break;
  default:
    dayName = "يوم غير صحيح";
}

console.log(dayName);  // "الثلاثاء"

// استخدام حالات مشتركة (Grouped cases)
let fruit = "تفاح";
let category;

switch (fruit) {
  case "تفاح":
  case "كمثرى":
  case "برتقال":
    category = "فواكه";
    break;
  case "طماطم":
  case "خيار":
  case "جزر":
    category = "خضروات";
    break;
  default:
    category = "غير معروف";
}

console.log(category);  // "فواكه"

// عدم استخدام break يؤدي إلى "fall-through"
let num = 3;
let message = "";

switch (num) {
  case 1:
    message = "واحد";
    // لاحظ عدم وجود break هنا
  case 2:
    message += " اثنان";
    // لاحظ عدم وجود break هنا
  case 3:
    message += " ثلاثة";
    break;
  case 4:
    message += " أربعة";
    break;
}

console.log(message);  // " ثلاثة" (بدأ التنفيذ من case 3)

حلقات for, for...in, for...of

حلقات التكرار تسمح لك بتكرار تنفيذ كود معين عدة مرات. هناك عدة أنواع من حلقات التكرار في جافا سكريبت.

مثال على حلقة for القياسية

// حلقة for الأساسية
for (let i = 0; i < 5; i++) {
  console.log(`Iteration ${i}`);
}
// النتيجة:
// Iteration 0
// Iteration 1
// Iteration 2
// Iteration 3
// Iteration 4

// حلقة for تتناقص
for (let i = 5; i > 0; i--) {
  console.log(`Countdown: ${i}`);
}

// حلقة for تقفز بخطوات متعددة
for (let i = 0; i <= 10; i += 2) {
  console.log(`Even numbers: ${i}`);
}

// حلقات for متداخلة
for (let i = 1; i <= 3; i++) {
  for (let j = 1; j <= 3; j++) {
    console.log(`i=${i}, j=${j}`);
  }
}

// المرور على عناصر مصفوفة باستخدام for
let fruits = ["تفاح", "موز", "برتقال", "عنب"];
for (let i = 0; i < fruits.length; i++) {
  console.log(fruits[i]);
}

// استخدام حلقة for...in للمرور على خصائص الكائن
let person = {
  name: "أحمد",
  age: 30,
  city: "القاهرة"
};

for (let key in person) {
  console.log(`${key}: ${person[key]}`);
}
// النتيجة:
// name: أحمد
// age: 30
// city: القاهرة

// استخدام حلقة for...in للمرور على عناصر مصفوفة (غير موصى به)
for (let index in fruits) {
  console.log(`${index}: ${fruits[index]}`);
}

// استخدام حلقة for...of للمرور على عناصر مصفوفة
for (let fruit of fruits) {
  console.log(fruit);
}
// النتيجة:
// تفاح
// موز
// برتقال
// عنب

// استخدام for...of مع النصوص
let text = "Hello";
for (let char of text) {
  console.log(char);
}
// النتيجة:
// H
// e
// l
// l
// o

// استخدام حلقة for...of مع Map (الخرائط)
let map = new Map([
  ["name", "محمد"],
  ["age", 25]
]);

for (let [key, value] of map) {
  console.log(`${key} = ${value}`);
}
// النتيجة:
// name = محمد
// age = 25

حلقات while و do...while

حلقات while و do...while تنفذ كتلة الكود طالما الشرط المحدد صحيح. الفرق الرئيسي بينهما هو أن حلقة do...while تنفذ الكود مرة واحدة على الأقل قبل التحقق من الشرط.

مثال على حلقات while و do...while

// حلقة while
let i = 0;
while (i < 5) {
  console.log(`while iteration ${i}`);
  i++;
}
// النتيجة:
// while iteration 0
// while iteration 1
// while iteration 2
// while iteration 3
// while iteration 4

// استخدام while مع شرط فوري (لن يتم تنفيذ الكود)
let j = 10;
while (j < 5) {
  console.log(`This won't be executed`);
  j++;
}

// حلقة do...while
let k = 0;
do {
  console.log(`do...while iteration ${k}`);
  k++;
} while (k < 5);
// النتيجة:
// do...while iteration 0
// do...while iteration 1
// do...while iteration 2
// do...while iteration 3
// do...while iteration 4

// استخدام do...while مع شرط فوري (سيتم تنفيذ الكود مرة واحدة على الأقل)
let m = 10;
do {
  console.log(`This will be executed once`);
  m++;
} while (m < 5);
// النتيجة:
// This will be executed once

// استخدام حلقة while للبحث في مصفوفة
let numbers = [4, 2, 8, 6, 1, 9];
let target = 6;
let index = 0;

while (index < numbers.length && numbers[index] !== target) {
  index++;
}

if (index < numbers.length) {
  console.log(`Found ${target} at index ${index}`);
} else {
  console.log(`${target} not found`);
}

// استخدام حلقة while لقراءة مدخلات المستخدم (تمثيل نظري)
/*
let input;
while (input !== "quit") {
  input = prompt("Enter a command (type 'quit' to exit):");
  console.log(`You entered: ${input}`);
}
*/

استخدام break و continue

تُستخدم عبارة break للخروج من حلقة التكرار أو عبارة switch. بينما تُستخدم عبارة continue لتخطي التكرار الحالي والانتقال إلى التكرار التالي في الحلقة.

مثال على استخدام break و continue

// استخدام break للخروج من الحلقة
for (let i = 0; i < 10; i++) {
  if (i === 5) {
    console.log("Breaking out of the loop");
    break;  // الخروج من الحلقة
  }
  console.log(`Iteration ${i}`);
}
// النتيجة:
// Iteration 0
// Iteration 1
// Iteration 2
// Iteration 3
// Iteration 4
// Breaking out of the loop

// استخدام continue لتخطي التكرار الحالي
for (let i = 0; i < 5; i++) {
  if (i === 2) {
    console.log("Skipping iteration 2");
    continue;  // تخطي التكرار الحالي
  }
  console.log(`Iteration ${i}`);
}
// النتيجة:
// Iteration 0
// Iteration 1
// Skipping iteration 2
// Iteration 3
// Iteration 4

// استخدام break في حلقات متداخلة
outerLoop: for (let i = 0; i < 3; i++) {
  for (let j = 0; j < 3; j++) {
    if (i === 1 && j === 1) {
      console.log("Breaking out of both loops");
      break outerLoop;  // الخروج من الحلقتين معاً باستخدام التسمية
    }
    console.log(`i=${i}, j=${j}`);
  }
}

// استخدام break للخروج من حلقة while
let i = 0;
while (true) {  // حلقة غير منتهية
  i++;
  if (i >= 5) {
    break;  // الخروج من الحلقة
  }
  console.log(`Iteration ${i}`);
}

// استخدام continue في حلقة while
let j = 0;
while (j < 5) {
  j++;
  if (j === 3) {
    console.log("Skipping iteration 3");
    continue;  // تخطي باقي التكرار الحالي
  }
  console.log(`Iteration ${j}`);
}

التعامل مع الأخطاء

تُستخدم عبارات try, catch, finally للتعامل مع الأخطاء في جافا سكريبت. يسمح هذا النهج بالتقاط الأخطاء ومعالجتها دون أن يتوقف تنفيذ البرنامج.

مثال على try, catch, finally

// مثال بسيط على try-catch
try {
  // كود قد يسبب خطأ
  console.log("Start of try block");
  noSuchVariable;  // هذا سيسبب خطأ لأن المتغير غير معرف
  console.log("End of try block");  // لن يتم تنفيذ هذا السطر
} catch (error) {
  // التعامل مع الخطأ
  console.log("An error occurred:");
  console.log(error.name);    // اسم الخطأ
  console.log(error.message); // رسالة الخطأ
}

// استخدام try-catch-finally
try {
  console.log("Start of try block");
  throw new Error("This is a custom error");  // إلقاء خطأ يدوياً
  console.log("End of try block");  // لن يتم تنفيذ هذا السطر
} catch (error) {
  console.log("Caught error:", error.message);
} finally {
  // سيتم تنفيذ هذا الكود دائماً، سواء حدث خطأ أم لا
  console.log("This always executes");
}

// أنواع الأخطاء المدمجة في جافا سكريبت
try {
  // SyntaxError
  // eval("if (true) {");  // خطأ في الصياغة

  // ReferenceError
  // nonExistentVariable;  // متغير غير موجود

  // TypeError
  // null.toString();      // استدعاء طريقة على null

  // RangeError
  // new Array(-1);        // إنشاء مصفوفة بطول سالب

  // URIError
  // decodeURI("%");       // تنسيق URI غير صالح
} catch (error) {
  if (error instanceof SyntaxError) {
    console.log("Syntax Error");
  } else if (error instanceof ReferenceError) {
    console.log("Reference Error");
  } else if (error instanceof TypeError) {
    console.log("Type Error");
  } else {
    console.log("Other error:", error.message);
  }
}

// إنشاء أخطاء مخصصة
class CustomError extends Error {
  constructor(message) {
    super(message);
    this.name = "CustomError";
  }
}

try {
  throw new CustomError("This is a custom error message");
} catch (error) {
  console.log(`${error.name}: ${error.message}`);
}

// استخدام try-catch مع async/await
async function fetchData() {
  try {
    // محاولة جلب البيانات
    let response = await fetch("https://api.example.com/data");
    let data = await response.json();
    return data;
  } catch (error) {
    // التعامل مع أي أخطاء
    console.log("Error fetching data:", error);
    return null;
  }
}

تعريف الدوال وأنواعها

الدوال (Functions) هي كتل من الكود يمكن استدعاؤها وإعادة استخدامها. هناك عدة طرق لتعريف الدوال في جافا سكريبت.

مثال على تعريف الدوال

// 1. تعريف الدالة باستخدام الإعلان (Function Declaration)
function greet(name) {
  return `Hello, ${name}!`;
}

console.log(greet("Ahmed"));  // "Hello, Ahmed!"

// 2. تعريف الدالة باستخدام التعبير (Function Expression)
const sayHello = function(name) {
  return `Hello, ${name}!`;
};

console.log(sayHello("Sara"));  // "Hello, Sara!"

// 3. تعريف الدالة باستخدام الدالة السهمية (Arrow Function)
const welcome = (name) => {
  return `Welcome, ${name}!`;
};

console.log(welcome("Mohammed"));  // "Welcome, Mohammed!"

// 4. الدالة السهمية مع عبارة واحدة (يمكن حذف الأقواس المتعرجة وكلمة return)
const add = (a, b) => a + b;

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

// 5. الدالة السهمية مع معامل واحد (يمكن حذف الأقواس حول المعاملات)
const square = x => x * x;

console.log(square(4));  // 16

// 6. دالة مجهولة (Anonymous Function)
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(function(num) {
  return num * 2;
});

console.log(doubled);  // [2, 4, 6, 8]

// 7. دالة رد النداء (Callback Function)
function processData(data, callback) {
  const processed = `Processed: ${data}`;
  callback(processed);
}

processData("Sample data", function(result) {
  console.log(result);  // "Processed: Sample data"
});

// 8. التعبير الذاتي التنفيذ للدالة (Immediately Invoked Function Expression - IIFE)
(function() {
  const privateVar = "I am private";
  console.log(privateVar);
})();
// privateVar is not accessible here

// 9. دالة بانية (Constructor Function)
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.greet = function() {
    return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
  };
}

const person1 = new Person("Ali", 25);
console.log(person1.greet());  // "Hello, my name is Ali and I am 25 years old."

// 10. طرق الكائن (Object Methods)
const calculator = {
  add: function(a, b) {
    return a + b;
  },
  // الصياغة المختصرة لطرق الكائن (ES6)
  subtract(a, b) {
    return a - b;
  }
};

console.log(calculator.add(10, 5));       // 15
console.log(calculator.subtract(10, 5));  // 5

المعاملات والوسائط

المعاملات (Parameters) هي المتغيرات التي تُعرَّف في تعريف الدالة. الوسائط (Arguments) هي القيم التي تُمرَّر إلى الدالة عند استدعائها.

مثال على المعاملات والوسائط

// معاملات أساسية
function add(a, b) {
  return a + b;
}

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

// معاملات افتراضية
function greet(name = "Guest") {
  return `Hello, ${name}!`;
}

console.log(greet("Ahmed"));  // "Hello, Ahmed!"
console.log(greet());         // "Hello, Guest!"

// معاملات متعددة متغيرة الطول (Rest Parameters)
function sum(...numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}

console.log(sum(1, 2, 3, 4, 5));  // 15
console.log(sum(10, 20));         // 30

// الدمج بين المعاملات العادية ومعاملات Rest
function multiply(multiplier, ...numbers) {
  return numbers.map(num => num * multiplier);
}

console.log(multiply(2, 1, 2, 3));  // [2, 4, 6]

// استخدام كائن arguments
function printArguments() {
  console.log(arguments.length);
  for (let i = 0; i < arguments.length; i++) {
    console.log(`Argument ${i}: ${arguments[i]}`);
  }
}

printArguments("a", "b", "c");
// النتيجة:
// 3
// Argument 0: a
// Argument 1: b
// Argument 2: c

// تمرير المعاملات بالقيمة (للأنواع البسيطة)
function incrementNumber(num) {
  num++;
  console.log(`Inside function: ${num}`);
}

let x = 5;
incrementNumber(x);  // "Inside function: 6"
console.log(x);      // 5 (القيمة الأصلية لم تتغير)

// تمرير المعاملات بالمرجع (للكائنات والمصفوفات)
function addProperty(obj) {
  obj.newProp = "Hello";
}

let myObj = { name: "Test" };
addProperty(myObj);
console.log(myObj);  // { name: "Test", newProp: "Hello" }

// استخدام التدمير (Destructuring) في المعاملات
function displayPerson({ name, age }) {
  console.log(`Name: ${name}, Age: ${age}`);
}

displayPerson({ name: "Sara", age: 28 });  // "Name: Sara, Age: 28"

// استخدام المصفوفات مع التدمير
function displayCoordinates([x, y]) {
  console.log(`X: ${x}, Y: ${y}`);
}

displayCoordinates([10, 20]);  // "X: 10, Y: 20"

إرجاع القيم (return)

تُستخدم عبارة return لإنهاء تنفيذ الدالة وإرجاع قيمة محددة. إذا لم يتم استخدام return، فستُرجع الدالة undefined.

مثال على إرجاع القيم

// إرجاع قيمة بسيطة
function add(a, b) {
  return a + b;  // إرجاع مجموع a و b
}

const sum = add(5, 3);
console.log(sum);  // 8

// عدم استخدام return يُرجع undefined
function greet(name) {
  console.log(`Hello, ${name}!`);
  // لا توجد عبارة return
}

const result = greet("Ahmed");
console.log(result);  // undefined

// استخدام return بدون قيمة (يُرجع undefined)
function checkAge(age) {
  if (age < 18) {
    return;  // الخروج مبكراً من الدالة
  }
  console.log("You are an adult");
}

console.log(checkAge(15));  // undefined

// إرجاع كائنات
function createPerson(name, age) {
  return {
    name: name,
    age: age,
    greet() {
      return `Hello, my name is ${this.name}`;
    }
  };
}

const person = createPerson("Mohammed", 30);
console.log(person.greet());  // "Hello, my name is Mohammed"

// إرجاع مصفوفات
function getRange(start, end) {
  const result = [];
  for (let i = start; i <= end; i++) {
    result.push(i);
  }
  return result;
}

console.log(getRange(1, 5));  // [1, 2, 3, 4, 5]

// إرجاع دوال (Closures)
function createMultiplier(factor) {
  return function(number) {
    return number * factor;
  };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5));  // 10
console.log(triple(5));  // 15

// إرجاع قيم متعددة باستخدام المصفوفات
function getStats(numbers) {
  const min = Math.min(...numbers);
  const max = Math.max(...numbers);
  const sum = numbers.reduce((total, num) => total + num, 0);
  const avg = sum / numbers.length;
  
  return [min, max, sum, avg];
}

const [min, max, sum, avg] = getStats([1, 5, 3, 9, 2]);
console.log(`Min: ${min}, Max: ${max}, Sum: ${sum}, Average: ${avg}`);

// إرجاع قيم متعددة باستخدام الكائنات
function getStatistics(numbers) {
  return {
    min: Math.min(...numbers),
    max: Math.max(...numbers),
    sum: numbers.reduce((total, num) => total + num, 0),
    avg: numbers.reduce((total, num) => total + num, 0) / numbers.length
  };
}

const stats = getStatistics([1, 5, 3, 9, 2]);
console.log(`Min: ${stats.min}, Max: ${stats.max}, Sum: ${stats.sum}, Average: ${stats.avg}`);

جرب بنفسك

يمكنك تجربة الدوال والمعاملات المختلفة في محرر الأكواد التفاعلي

فتح محرر الأكواد

الدوال السهمية

الدوال السهمية (Arrow Functions) هي طريقة مختصرة لكتابة الدوال في جافا سكريبت، تم تقديمها في ES6. تتميز بصياغتها المختصرة وبأنها لا تمتلك this خاص بها.

مثال على الدوال السهمية

// دالة تقليدية
function add1(a, b) {
return a + b;
}

// نفس الدالة كدالة سهمية
const add2 = (a, b) => {
return a + b;
};

// دالة سهمية مختصرة (بدون كتلة وبدون return)
const add3 = (a, b) => a + b;

console.log(add1(2, 3));  // 5
console.log(add2(2, 3));  // 5
console.log(add3(2, 3));  // 5

// دالة سهمية بمعامل واحد (يمكن حذف الأقواس)
const square1 = (x) => x * x;
const square2 = x => x * x;  // نفس الدالة بشكل مختصر

console.log(square1(4));  // 16
console.log(square2(4));  // 16

// دالة سهمية بدون معاملات
const sayHello = () => "Hello, World!";
console.log(sayHello());  // "Hello, World!"

// إرجاع كائن في دالة سهمية (يجب استخدام أقواس حول الكائن)
const createPerson = (name, age) => ({ name, age });
console.log(createPerson("Ahmed", 30));  // { name: "Ahmed", age: 30 }

// الفرق في this بين الدوال التقليدية والدوال السهمية
const person = {
name: "Sara",
traditionalFunction: function() {
console.log(`Traditional function: ${this.name}`);
},
arrowFunction: () => {
console.log(`Arrow function: ${this.name}`);  // this يشير إلى السياق الخارجي
}
};

person.traditionalFunction();  // "Traditional function: Sara"
person.arrowFunction();        // "Arrow function: undefined"

// استخدام الدوال السهمية في دوال رد النداء
const numbers = [1, 2, 3, 4, 5];

// طريقة تقليدية
const doubledTraditional = numbers.map(function(num) {
return num * 2;
});

// باستخدام الدالة السهمية
const doubledArrow = numbers.map(num => num * 2);

console.log(doubledTraditional);  // [2, 4, 6, 8, 10]
console.log(doubledArrow);        // [2, 4, 6, 8, 10]

// استخدام this في دوال رد النداء
function Counter() {
this.count = 0;

// باستخدام الدالة التقليدية (مع مشكلة this)
setInterval(function() {
this.count++;  // this لا يشير إلى كائن Counter
console.log(this.count);  // NaN
}, 1000);

// باستخدام الدالة السهمية (حل مشكلة this)
/* 
setInterval(() => {
this.count++;  // this يشير إلى كائن Counter
console.log(this.count);  // يزيد بشكل صحيح
}, 1000);
*/
}

نطاق المتغيرات

نطاق المتغير (Scope) يحدد مدى إمكانية الوصول إلى المتغير في الكود. هناك ثلاثة أنواع رئيسية من النطاقات في جافا سكريبت: النطاق العالمي، ونطاق الدالة، ونطاق الكتلة.

مثال على نطاق المتغيرات

// النطاق العالمي (Global Scope)
const globalVar = "I am global";  // متغير عالمي

function testScope() {
console.log(globalVar);  // يمكن الوصول إلى المتغير العالمي هنا
}

testScope();  // "I am global"
console.log(globalVar);  // "I am global"

// نطاق الدالة (Function Scope)
function functionScope() {
const functionVar = "I am function scoped";  // متغير في نطاق الدالة
console.log(functionVar);  // "I am function scoped"
}

functionScope();
// console.log(functionVar);  // خطأ: functionVar غير معرف خارج الدالة

// var vs let/const في نطاق الكتلة
function blockScope() {
if (true) {
var varVariable = "I am var";  // متاح في نطاق الدالة كلها
let letVariable = "I am let";  // متاح فقط في نطاق الكتلة
const constVariable = "I am const";  // متاح فقط في نطاق الكتلة
}

console.log(varVariable);  // "I am var"
// console.log(letVariable);  // خطأ: letVariable غير معرف خارج الكتلة
// console.log(constVariable);  // خطأ: constVariable غير معرف خارج الكتلة
}

blockScope();

// النطاقات المتداخلة (Nested Scopes)
function outer() {
const outerVar = "I am from outer function";

function inner() {
const innerVar = "I am from inner function";
console.log(outerVar);  // يمكن الوصول إلى المتغير من الدالة الخارجية
console.log(innerVar);
}

inner();
// console.log(innerVar);  // خطأ: innerVar غير معرف في الدالة الخارجية
}

outer();

// إخفاء المتغيرات (Variable Shadowing)
const value = "global";

function shadowTest() {
const value = "local";  // هذا المتغير "يخفي" المتغير العالمي بنفس الاسم
console.log(value);  // "local"
}

shadowTest();
console.log(value);  // "global"

// ارتفاع المتغيرات (Hoisting)
console.log(hoistedVar);  // undefined (تم رفع الإعلان ولكن ليس التهيئة)
var hoistedVar = "I am hoisted";

// console.log(letVar);  // خطأ: letVar غير معرف (لا يتم رفع let)
let letVar = "I am not hoisted";

// الإغلاقات (Closures)
function createCounter() {
let count = 0;  // متغير خاص في نطاق الدالة

return function() {
count++;  // الدالة المرجعة يمكنها الوصول إلى count
return count;
};
}

const counter = createCounter();
console.log(counter());  // 1
console.log(counter());  // 2
console.log(counter());  // 3

المصفوفات (Arrays)

المصفوفات هي هياكل بيانات تُستخدم لتخزين مجموعات من القيم في متغير واحد. يمكن أن تحتوي المصفوفة على أنواع بيانات مختلفة.

مثال على المصفوفات

// إنشاء مصفوفات
let fruits = ["apple", "banana", "orange"];  // إنشاء مصفوفة بعناصر
let emptyArray = [];  // مصفوفة فارغة
let mixedArray = [1, "hello", true, null, { name: "John" }, [1, 2, 3]];  // مصفوفة بأنواع مختلفة
let arrayConstructor = new Array(3);  // مصفوفة بطول 3 (عناصر فارغة)

// الوصول إلى عناصر المصفوفة
console.log(fruits[0]);  // "apple" (الفهرس يبدأ من 0)
console.log(fruits[1]);  // "banana"
console.log(fruits[fruits.length - 1]);  // "orange" (آخر عنصر)

// تعديل عناصر المصفوفة
fruits[1] = "grape";
console.log(fruits);  // ["apple", "grape", "orange"]

// خصائص المصفوفة
console.log(fruits.length);  // 3 (عدد العناصر)

// إضافة عناصر إلى المصفوفة
fruits.push("mango");  // إضافة عنصر في النهاية
console.log(fruits);  // ["apple", "grape", "orange", "mango"]

fruits.unshift("strawberry");  // إضافة عنصر في البداية
console.log(fruits);  // ["strawberry", "apple", "grape", "orange", "mango"]

// حذف عناصر من المصفوفة
let lastFruit = fruits.pop();  // حذف وإرجاع آخر عنصر
console.log(lastFruit);  // "mango"
console.log(fruits);  // ["strawberry", "apple", "grape", "orange"]

let firstFruit = fruits.shift();  // حذف وإرجاع أول عنصر
console.log(firstFruit);  // "strawberry"
console.log(fruits);  // ["apple", "grape", "orange"]

// طرق المصفوفات الأساسية
// دمج مصفوفتين
let moreFruits = ["kiwi", "pineapple"];
let allFruits = fruits.concat(moreFruits);
console.log(allFruits);  // ["apple", "grape", "orange", "kiwi", "pineapple"]

// قطع جزء من المصفوفة
let someFruits = allFruits.slice(1, 4);  // من الفهرس 1 إلى 4 (غير متضمن)
console.log(someFruits);  // ["grape", "orange", "kiwi"]

// جعل المصفوفة سلسلة نصية
console.log(allFruits.join(", "));  // "apple, grape, orange, kiwi, pineapple"

// البحث في المصفوفة
console.log(allFruits.indexOf("kiwi"));  // 3 (فهرس العنصر)
console.log(allFruits.includes("banana"));  // false (هل تحتوي المصفوفة على العنصر)

// حذف/إضافة/استبدال عناصر
allFruits.splice(2, 1);  // حذف عنصر واحد من الفهرس 2
console.log(allFruits);  // ["apple", "grape", "kiwi", "pineapple"]

allFruits.splice(2, 0, "melon", "plum");  // إضافة عناصر من الفهرس 2 بدون حذف
console.log(allFruits);  // ["apple", "grape", "melon", "plum", "kiwi", "pineapple"]

allFruits.splice(1, 2, "peach");  // استبدال عنصرين بعنصر واحد
console.log(allFruits);  // ["apple", "peach", "plum", "kiwi", "pineapple"]

// ترتيب المصفوفة
allFruits.sort();  // ترتيب تصاعدي
console.log(allFruits);  // ترتيب أبجدي

allFruits.reverse();  // عكس ترتيب المصفوفة
console.log(allFruits);

// المصفوفات متعددة الأبعاد
let matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];

console.log(matrix[1][2]);  // 6 (الصف 1، العمود 2)

طرق المصفوفات المتقدمة

توفر جافا سكريبت العديد من الطرق المتقدمة للتعامل مع المصفوفات، وخاصة الطرق الوظيفية مثل map و filter و reduce والتي تسهل معالجة البيانات.

مثال على طرق المصفوفات المتقدمة

// بيانات للأمثلة
const people = [
{ name: "Ahmed", age: 28, city: "Cairo" },
{ name: "Sara", age: 22, city: "Alexandria" },
{ name: "Mohammed", age: 35, city: "Cairo" },
{ name: "Layla", age: 17, city: "Aswan" },
{ name: "Omar", age: 40, city: "Alexandria" }
];

// map() - إنشاء مصفوفة جديدة بتطبيق دالة على كل عنصر
const names = people.map(person => person.name);
console.log(names);  // ["Ahmed", "Sara", "Mohammed", "Layla", "Omar"]

// تحويل المصفوفة إلى شكل آخر
const formattedPeople = people.map(person => ({
fullName: person.name,
yearOfBirth: new Date().getFullYear() - person.age
}));
console.log(formattedPeople);

// filter() - إنشاء مصفوفة جديدة مع العناصر التي تحقق شرط معين
const adults = people.filter(person => person.age >= 18);
console.log(adults);  // كل العناصر ما عدا Layla

// الجمع بين filter و map
const adultNames = people
.filter(person => person.age >= 18)
.map(person => person.name);
console.log(adultNames);  // ["Ahmed", "Sara", "Mohammed", "Omar"]

// find() - البحث عن أول عنصر يحقق شرط معين
const sara = people.find(person => person.name === "Sara");
console.log(sara);  // { name: "Sara", age: 22, city: "Alexandria" }

// findIndex() - البحث عن فهرس أول عنصر يحقق شرط معين
const laylaIndex = people.findIndex(person => person.name === "Layla");
console.log(laylaIndex);  // 3

// some() - هل يوجد عنصر واحد على الأقل يحقق الشرط
const hasTeenagers = people.some(person => person.age < 18);
console.log(hasTeenagers);  // true

// every() - هل تحقق جميع العناصر الشرط
const allAdults = people.every(person => person.age >= 18);
console.log(allAdults);  // false

// reduce() - تقليص المصفوفة إلى قيمة واحدة
const totalAge = people.reduce((sum, person) => sum + person.age, 0);
console.log(totalAge);  // 142 (مجموع الأعمار)

// استخدام reduce لإنشاء كائن
const peopleByCity = people.reduce((acc, person) => {
// إذا لم تكن المدينة موجودة، أنشئ مصفوفة فارغة
if (!acc[person.city]) {
acc[person.city] = [];
}
// أضف الشخص إلى المدينة المناسبة
acc[person.city].push(person);
return acc;
}, {});

console.log(peopleByCity);
// { Cairo: [2 شخص], Alexandria: [2 شخص], Aswan: [1 شخص] }

// sort() - ترتيب العناصر
// ترتيب الأشخاص حسب العمر تصاعدياً
const sortedByAge = [...people].sort((a, b) => a.age - b.age);
console.log(sortedByAge);

// ترتيب الأشخاص حسب الاسم أبجدياً
const sortedByName = [...people].sort((a, b) => a.name.localeCompare(b.name));
console.log(sortedByName);

// flat() - دمج المصفوفات المتداخلة
const nestedArray = [1, [2, 3], [4, [5, 6]]];
console.log(nestedArray.flat());  // [1, 2, 3, 4, [5, 6]]
console.log(nestedArray.flat(2));  // [1, 2, 3, 4, 5, 6]

// flatMap() - دمج بين map و flat
const sentences = ["Hello world", "How are you"];
const words = sentences.flatMap(sentence => sentence.split(" "));
console.log(words);  // ["Hello", "world", "How", "are", "you"]

الكائنات (Objects)

الكائنات في جافا سكريبت هي هياكل بيانات تخزن مجموعات من القيم في شكل أزواج من الخصائص والقيم.

مثال على الكائنات

// إنشاء كائن بسيط
const person = {
firstName: "Ahmed",
lastName: "Ali",
age: 30,
city: "Cairo"
};

// الوصول إلى خصائص الكائن
console.log(person.firstName);  // "Ahmed" (طريقة النقطة)
console.log(person["lastName"]);  // "Ali" (طريقة الأقواس المربعة)

// تعديل خاصية
person.age = 31;
person["city"] = "Alexandria";

// إضافة خصائص جديدة
person.email = "[email protected]";
person["isEmployed"] = true;

console.log(person);
// { firstName: "Ahmed", lastName: "Ali", age: 31, city: "Alexandria", email: "[email protected]", isEmployed: true }

// حذف خاصية
delete person.isEmployed;
console.log(person);

// التحقق من وجود خاصية
console.log("email" in person);  // true
console.log(person.hasOwnProperty("phone"));  // false

// استخدام متغير للوصول إلى خاصية
const propertyName = "age";
console.log(person[propertyName]);  // 31

// طرق وخصائص متداخلة
const user = {
name: "Sara",
address: {
street: "123 Main St",
city: "Luxor",
country: "Egypt"
},
hobbies: ["reading", "swimming", "coding"],
greet: function() {
return `Hello, my name is ${this.name}`;
},
// طريقة مختصرة لتعريف دالة (ES6)
sayHello() {
return `Hi from ${this.name}`;
}
};

console.log(user.address.city);  // "Luxor"
console.log(user.hobbies[1]);  // "swimming"
console.log(user.greet());  // "Hello, my name is Sara"

// تكرار الكائنات
// المراجع تشير إلى نفس الكائن
const user2 = user;
user2.name = "Mohammed";
console.log(user.name);  // "Mohammed" (تغير في الكائن الأصلي أيضاً)

// نسخ ضحلة للكائن (لا تنسخ الكائنات المتداخلة)
const user3 = Object.assign({}, user);
// أو باستخدام عامل الانتشار:
const user4 = { ...user };

user3.name = "Layla";
console.log(user.name);  // "Mohammed" (لم يتغير)
console.log(user3.name);  // "Layla"

// لكن الكائنات والمصفوفات المتداخلة لا تزال مشتركة
user3.address.city = "Aswan";
console.log(user.address.city);  // "Aswan" (تغير في الكائن الأصلي)

// نسخ عميقة (لنسخ الكائنات المتداخلة)
const user5 = JSON.parse(JSON.stringify(user));
user5.address.city = "Cairo";
console.log(user.address.city);  // "Aswan" (لم يتغير)
console.log(user5.address.city);  // "Cairo"

// استخدام Object.keys()، Object.values()، Object.entries()
console.log(Object.keys(person));  // ["firstName", "lastName", "age", "city", "email"]
console.log(Object.values(person));  // ["Ahmed", "Ali", 31, "Alexandria", "[email protected]"]
console.log(Object.entries(person));  // [["firstName", "Ahmed"], ["lastName", "Ali"], ...]

// المرور على خصائص الكائن
for (let key in person) {
console.log(`${key}: ${person[key]}`);
}

// الكائنات المجمدة (لا يمكن تعديلها)
const frozenObj = Object.freeze({
id: 1,
name: "Cannot be modified"
});

// frozenObj.name = "Changed";  // لن يحدث أي تغيير (في وضع strict سيظهر خطأ)
console.log(frozenObj.name);  // "Cannot be modified"

البرمجة كائنية التوجه في جافا سكريبت

البرمجة كائنية التوجه (OOP) هي نموذج برمجي يعتمد على مفهوم "الكائنات" التي تحتوي على بيانات وشيفرة معاً. في جافا سكريبت، يمكن تنفيذ البرمجة كائنية التوجه بعدة طرق.

الفئات (Classes) في جافا سكريبت

تم تقديم الفئات في ES6 كطريقة أسهل للتعامل مع البرمجة كائنية التوجه، رغم أنها في الأساس مجرد صياغة سكرية فوق نموذج البروتوتايب (Prototype) الموجود مسبقاً.

مثال على الفئات في جافا سكريبت

// تعريف فئة بسيطة
class Person {
// دالة المنشئ
constructor(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}

// طريقة (method)
getFullName() {
return `${this.firstName} ${this.lastName}`;
}

// طريقة
greet() {
return `Hello, my name is ${this.getFullName()}`;
}

// طريقة ثابتة (static method) - تنتمي للفئة نفسها، وليس للكائنات
static createAnonymous() {
return new Person("Anonymous", "User", 0);
}
}

// إنشاء كائن من الفئة
const person1 = new Person("Ahmed", "Ali", 30);
console.log(person1.getFullName());  // "Ahmed Ali"
console.log(person1.greet());  // "Hello, my name is Ahmed Ali"

// استدعاء طريقة ثابتة
const anonymous = Person.createAnonymous();
console.log(anonymous.getFullName());  // "Anonymous User"

// ميزات متقدمة - الإغلاقات لإنشاء خصائص خاصة
class BankAccount {
constructor(owner, initialBalance) {
this.owner = owner;
// استخدام متغير محلي كخاصية خاصة
let balance = initialBalance;

// طرق عامة للتعامل مع الخاصية الخاصة
this.getBalance = function() {
return balance;
};

this.deposit = function(amount) {
if (amount > 0) {
balance += amount;
return true;
}
return false;
};

this.withdraw = function(amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return true;
}
return false;
};
}
}

const account = new BankAccount("Sara", 1000);
console.log(account.getBalance());  // 1000
account.deposit(500);
console.log(account.getBalance());  // 1500
account.withdraw(200);
console.log(account.getBalance());  // 1300
// console.log(account.balance);  // undefined (الخاصية خاصة)

// استخدام الدوال المُعدِّلة والمُستَرجِعة (getters/setters)
class Circle {
constructor(radius) {
this._radius = radius;  // اصطلاح: _ للإشارة إلى أنها خاصية شبه خاصة
}

// getter
get radius() {
return this._radius;
}

// setter
set radius(value) {
if (value > 0) {
this._radius = value;
} else {
console.error("Radius must be positive");
}
}

// getter لحساب المساحة
get area() {
return Math.PI * this._radius ** 2;
}

// getter لحساب المحيط
get circumference() {
return 2 * Math.PI * this._radius;
}
}

const circle = new Circle(5);
console.log(circle.radius);  // 5
console.log(circle.area);    // ~78.54
circle.radius = 7;
console.log(circle.radius);  // 7
console.log(circle.area);    // ~153.94
circle.radius = -2;          // خطأ: Radius must be positive
console.log(circle.radius);  // 7 (لم يتغير)

الوراثة (Inheritance)

الوراثة هي آلية تسمح لفئة بوراثة خصائص وطرق من فئة أخرى. في جافا سكريبت، تُستخدم كلمة extends للوراثة.

مثال على الوراثة في جافا سكريبت

// الفئة الأساسية
class Animal {
constructor(name) {
this.name = name;
}

speak() {
return `${this.name} makes a noise.`;
}

eat() {
return `${this.name} is eating.`;
}
}

// فئة مشتقة (ترث من Animal)
class Dog extends Animal {
constructor(name, breed) {
super(name);  // استدعاء منشئ الفئة الأساسية
this.breed = breed;
}

// تجاوز طريقة الفئة الأساسية
speak() {
return `${this.name} barks.`;
}

// إضافة طريقة جديدة
fetch() {
return `${this.name} fetches the ball.`;
}
}

// فئة مشتقة أخرى
class Cat extends Animal {
constructor(name, color) {
super(name);
this.color = color;
}

speak() {
return `${this.name} meows.`;
}

climb() {
return `${this.name} climbs a tree.`;
}
}

// إنشاء كائنات
const animal = new Animal("Generic Animal");
const dog = new Dog("Rex", "German Shepherd");
const cat = new Cat("Luna", "Gray");

// استدعاء الطرق
console.log(animal.speak());  // "Generic Animal makes a noise."
console.log(dog.speak());     // "Rex barks."
console.log(cat.speak());     // "Luna meows."

// الطرق الموروثة
console.log(dog.eat());       // "Rex is eating."
console.log(cat.eat());       // "Luna is eating."

// الطرق الخاصة بالفئات المشتقة
console.log(dog.fetch());     // "Rex fetches the ball."
console.log(cat.climb());     // "Luna climbs a tree."

// التحقق من نوع الكائن
console.log(dog instanceof Dog);       // true
console.log(dog instanceof Animal);    // true
console.log(dog instanceof Object);    // true
console.log(cat instanceof Dog);       // false

// استدعاء طريقة الفئة الأساسية من الفئة المشتقة
class Bird extends Animal {
speak() {
// استدعاء طريقة الفئة الأساسية أولاً
const originalMessage = super.speak();
return `${originalMessage} But this bird chirps.`;
}
}

const bird = new Bird("Tweetie");
console.log(bird.speak());  // "Tweetie makes a noise. But this bird chirps."

البرمجة غير المتزامنة في جافا سكريبت

البرمجة غير المتزامنة (Asynchronous Programming) تسمح بتنفيذ الكود دون حظر العمليات الأخرى. وهي ضرورية في جافا سكريبت للتعامل مع العمليات التي تستغرق وقتاً، مثل طلبات الشبكة وقراءة الملفات والتأخيرات الزمنية.

مثال على الدوال رد النداء (Callbacks)

// دالة رد النداء بسيطة
function doSomethingAsync(callback) {
  console.log("Starting async operation...");
  
  // محاكاة عملية غير متزامنة باستخدام setTimeout
  setTimeout(function() {
    console.log("Async operation completed");
    const result = 42;
    callback(result);
  }, 2000);
}

// استدعاء الدالة غير المتزامنة
console.log("Before async call");
doSomethingAsync(function(result) {
  console.log(`Got result: ${result}`);
});
console.log("After async call (but before callback)");

// النتيجة:
// "Before async call"
// "Starting async operation..."
// "After async call (but before callback)"
// (بعد ثانيتين)
// "Async operation completed"
// "Got result: 42"

الوعود (Promises)

الوعود (Promises) هي كائنات تمثل نتيجة عملية غير متزامنة قد تكتمل (أو تفشل) في المستقبل. تم تقديمها في ES6 لتحسين التعامل مع العمليات غير المتزامنة وتجنب "جحيم الاستدعاءات" (callback hell).

مثال على الوعود

// إنشاء وعد بسيط
const myPromise = new Promise((resolve, reject) => {
  // محاكاة عملية غير متزامنة
  const success = true;  // غيّر إلى false لمحاكاة الفشل
  
  setTimeout(() => {
    if (success) {
      resolve("Operation successful!");  // الوعد نجح
    } else {
      reject("Operation failed!");  // الوعد فشل
    }
  }, 2000);
});

// استخدام الوعد
console.log("Before promise");
myPromise
  .then(result => {
    console.log(`Success: ${result}`);
  })
  .catch(error => {
    console.log(`Error: ${error}`);
  })
  .finally(() => {
    console.log("Promise settled (either fulfilled or rejected)");
  });
console.log("After promise (but before it settles)");

// تحويل دالة رد النداء إلى دالة تعيد وعداً
function doSomethingWithPromise() {
  return new Promise((resolve, reject) => {
    console.log("Starting promise operation...");
    setTimeout(() => {
      const result = 42;
      resolve(result);
    }, 2000);
  });
}

// استخدام الدالة التي تعيد وعداً
doSomethingWithPromise()
  .then(result => {
    console.log(`Got result: ${result}`);
    return result * 2;  // إرجاع قيمة للـ then التالي
  })
  .then(doubledResult => {
    console.log(`Doubled result: ${doubledResult}`);
    return doubledResult + 10;  // إرجاع قيمة للـ then التالي
  })
  .then(finalResult => {
    console.log(`Final result: ${finalResult}`);
  })
  .catch(error => {
    console.log(`Error: ${error}`);
  });

// سلسلة الوعود - محاكاة طلبات متتالية
function fetchUserData(userId) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(`Fetched user data for user ${userId}`);
      resolve({ id: userId, name: "User " + userId });
    }, 1000);
  });
}

function fetchUserPosts(user) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(`Fetched posts for ${user.name}`);
      resolve({ user, posts: ["Post 1", "Post 2", "Post 3"] });
    }, 1000);
  });
}

function fetchPostComments(posts) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(`Fetched comments for posts`);
      resolve({ 
        ...posts, 
        comments: ["Comment 1", "Comment 2"]
      });
    }, 1000);
  });
}

// استخدام سلسلة الوعود
fetchUserData(1)
  .then(user => fetchUserPosts(user))
  .then(userWithPosts => fetchPostComments(userWithPosts))
  .then(result => {
    console.log("Final result:", result);
  })
  .catch(error => {
    console.log("Error in chain:", error);
  });

// Promise.all - تنفيذ مجموعة من الوعود بالتوازي
const promise1 = new Promise(resolve => setTimeout(() => resolve("One"), 1000));
const promise2 = new Promise(resolve => setTimeout(() => resolve("Two"), 2000));
const promise3 = new Promise(resolve => setTimeout(() => resolve("Three"), 1500));

Promise.all([promise1, promise2, promise3])
  .then(results => {
    console.log("All promises resolved:", results);
    // ["One", "Two", "Three"]
  })
  .catch(error => {
    console.log("At least one promise rejected:", error);
  });

// Promise.race - تنفيذ أول وعد ينتهي
Promise.race([promise1, promise2, promise3])
  .then(result => {
    console.log("First promise to resolve:", result);
    // "One" (أسرع وعد)
  })
  .catch(error => {
    console.log("First promise to reject:", error);
  });

Async/Await

تم تقديم async/await في ES2017 كطريقة أبسط للتعامل مع الوعود. وهي تسمح بكتابة كود غير متزامن يبدو ويتصرف مثل الكود المتزامن.

مثال على async/await

// دالة async بسيطة
async function helloAsync() {
  return "Hello, Async!";  // يتم تغليف القيمة المرجعة في وعد
}

// الدالة async تعيد دائماً وعداً
console.log(helloAsync());  // Promise {: "Hello, Async!"}

// استخدام وعد معاد من دالة async
helloAsync().then(result => {
  console.log(result);  // "Hello, Async!"
});

// استخدام await للانتظار حتى اكتمال وعد
async function fetchData() {
  // محاكاة عملية غير متزامنة
  const fetchPromise = new Promise(resolve => {
    setTimeout(() => resolve("Data fetched!"), 2000);
  });
  
  console.log("Fetching data...");
  const result = await fetchPromise;  // ينتظر حتى يكتمل الوعد
  console.log("After await");
  
  return result;
}

// استدعاء الدالة async
console.log("Before calling fetchData");
fetchData().then(result => {
  console.log(`Result: ${result}`);
});
console.log("After calling fetchData (but before it completes)");

// التعامل مع الأخطاء في async/await
async function fetchWithErrorHandling() {
  try {
    // محاكاة طلب قد ينجح أو يفشل
    const fetchPromise = new Promise((resolve, reject) => {
      const success = false;  // غيّر إلى true لمحاكاة النجاح
      setTimeout(() => {
        if (success) {
          resolve("Data fetched successfully!");
        } else {
          reject("Failed to fetch data");
        }
      }, 2000);
    });
    
    const result = await fetchPromise;
    console.log(`Success: ${result}`);
    return result;
  } catch (error) {
    console.log(`Error caught: ${error}`);
    // يمكن أيضاً إعادة رمي الخطأ أو إرجاع قيمة بديلة
    return "Fallback value";
  } finally {
    console.log("This runs regardless of success or failure");
  }
}

fetchWithErrorHandling().then(result => {
  console.log(`Final result: ${result}`);
});

// سلسلة العمليات غير المتزامنة باستخدام async/await
async function fetchUserDataSequence() {
  try {
    // دوال fetchUserData و fetchUserPosts و fetchPostComments من المثال السابق
    
    // بدلاً من سلسلة وعود، يمكننا استخدام أسلوب أكثر قرائية
    const user = await fetchUserData(1);
    const userWithPosts = await fetchUserPosts(user);
    const result = await fetchPostComments(userWithPosts);
    
    console.log("Final result with async/await:", result);
    return result;
  } catch (error) {
    console.log("Error in async sequence:", error);
  }
}

fetchUserDataSequence();

// استخدام عمليات متوازية مع async/await
async function parallelFetches() {
  try {
    // تشغيل العمليات بالتوازي
    const userPromise = fetchUserData(1);
    const postsPromise = fetchUserData(2);
    const commentsPromise = fetchUserData(3);
    
    // الانتظار حتى تكتمل جميع العمليات
    const [user, posts, comments] = await Promise.all([
      userPromise, postsPromise, commentsPromise
    ]);
    
    console.log("All data fetched in parallel:", { user, posts, comments });
  } catch (error) {
    console.log("Error in parallel fetches:", error);
  }
}

parallelFetches();

نموذج كائن المستند (DOM)

نموذج كائن المستند (Document Object Model - DOM) هو واجهة برمجة تطبيقات (API) للصفحات HTML وXML. يقدم DOM تمثيلاً هيكلياً للمستند، ويسمح للبرامج بتغيير محتوى ومظهر وهيكل المستند.

مثال على التعامل مع DOM

// الوصول إلى عناصر DOM
// باستخدام المعرف
const element = document.getElementById("myElement");

// باستخدام اسم العنصر
const paragraphs = document.getElementsByTagName("p");

// باستخدام اسم الفئة
const highlights = document.getElementsByClassName("highlight");

// باستخدام محددات CSS (modern approach)
const firstButton = document.querySelector("button");
const allButtons = document.querySelectorAll("button.primary");

// الوصول إلى عقد ذات صلة
const parent = element.parentNode;
const children = element.childNodes;
const firstChild = element.firstChild;
const lastChild = element.lastChild;
const nextSibling = element.nextSibling;
const previousSibling = element.previousSibling;

// التعامل مع المحتوى
// تعيين/قراءة محتوى HTML
element.innerHTML = "New HTML content";
console.log(element.innerHTML);

// تعيين/قراءة محتوى نصي
element.textContent = "New text content";
console.log(element.textContent);

// إنشاء وإدراج عناصر جديدة
const newParagraph = document.createElement("p");
newParagraph.textContent = "This is a new paragraph";
document.body.appendChild(newParagraph);

// إنشاء وإدراج نص
const textNode = document.createTextNode("Some new text");
element.appendChild(textNode);

// إدراج عنصر قبل عنصر آخر
const referenceElement = document.getElementById("referenceElement");
const newElement = document.createElement("div");
newElement.textContent = "Inserted before reference";
referenceElement.parentNode.insertBefore(newElement, referenceElement);

// استبدال عنصر
const oldElement = document.getElementById("oldElement");
const replacement = document.createElement("span");
replacement.textContent = "Replacement element";
oldElement.parentNode.replaceChild(replacement, oldElement);

// حذف عنصر
const elementToRemove = document.getElementById("elementToRemove");
elementToRemove.parentNode.removeChild(elementToRemove);
// أو الطريقة الحديثة
// elementToRemove.remove();

// التعامل مع السمات
// تعيين سمة
element.setAttribute("class", "active");

// قراءة سمة
const className = element.getAttribute("class");

// التحقق من وجود سمة
const hasAttribute = element.hasAttribute("disabled");

// حذف سمة
element.removeAttribute("disabled");

// التعامل مع الفئات CSS
element.classList.add("new-class");
element.classList.remove("old-class");
element.classList.toggle("toggle-class");
const hasClass = element.classList.contains("some-class");

// التعامل مع الأنماط CSS
element.style.color = "red";
element.style.fontSize = "16px";
element.style.backgroundColor = "lightgray";
console.log(element.style.color);

// الحصول على الأنماط المحسوبة
const computedStyle = window.getComputedStyle(element);
console.log(computedStyle.color);

// التعامل مع الأحداث
function handleClick(event) {
  console.log("Button clicked");
  console.log("Event:", event);
  console.log("Target:", event.target);
}

// إضافة مستمع للأحداث
element.addEventListener("click", handleClick);

// إزالة مستمع للأحداث
element.removeEventListener("click", handleClick);

// أحداث DOM الشائعة:
// click, dblclick, mousedown, mouseup, mouseover, mouseout, mousemove
// keydown, keyup, keypress
// focus, blur, change, submit, input
// load, resize, scroll

// التفويض (Event Delegation)
document.getElementById("parent-container").addEventListener("click", function(event) {
  if (event.target.classList.contains("child-button")) {
    console.log("Child button clicked");
  }
});

وحدات JavaScript (Modules)

الوحدات (Modules) تسمح بتنظيم الكود في ملفات منفصلة، بحيث يمكن استيراد وتصدير الدوال والمتغيرات بين الملفات. تم إدخال الوحدات رسمياً في ES6.

مثال على وحدات JavaScript

// math.js - ملف وحدة
// تصدير دوال ومتغيرات فردية
export const PI = 3.14159;

export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

// دالة خاصة (لن يتم تصديرها)
function square(x) {
  return x * x;
}

// تصدير دالة كتصدير افتراضي
export default function multiply(a, b) {
  return a * b;
}

// app.js - استيراد الوحدة
// استيراد كائنات محددة
import { add, subtract, PI } from './math.js';

console.log(add(5, 3));        // 8
console.log(subtract(10, 4));  // 6
console.log(PI);               // 3.14159

// استيراد التصدير الافتراضي
import multiply from './math.js';
console.log(multiply(4, 5));   // 20

// استيراد كل الصادرات ككائن واحد
import * as MathModule from './math.js';
console.log(MathModule.add(2, 3));     // 5
console.log(MathModule.PI);            // 3.14159
console.log(MathModule.default(3, 4)); // 12 (الدالة الافتراضية)

// استيراد مع إعادة تسمية
import { add as sum, PI as MATH_PI } from './math.js';
console.log(sum(7, 8));    // 15
console.log(MATH_PI);      // 3.14159

// user.js - وحدة أخرى
export class User {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  
  greet() {
    return `Hello, I'm ${this.name}`;
  }
}

// تصدير دوال مجمعة
export { 
  createUser, 
  validateUser 
};

function createUser(name, age) {
  return new User(name, age);
}

function validateUser(user) {
  return user.age >= 18;
}

// utils.js - وحدة إضافية
const utils = {
  formatDate(date) {
    return date.toLocaleDateString();
  },
  capitalize(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }
};

// تصدير كائن موجود مسبقاً
export default utils;

// main.js - استيراد من وحدات متعددة
import multiply from './math.js';
import { User, createUser } from './user.js';
import utils from './utils.js';

const user = createUser('Ahmed', 25);
console.log(user.greet());                   // "Hello, I'm Ahmed"
console.log(utils.capitalize(user.name));    // "Ahmed"

استمر في التعلم

هذا التوثيق يغطي الأساسيات الرئيسية للغة جافا سكريبت، لكن هناك المزيد لاكتشافه. تحقق من قسم الموارد التعليمية لمزيد من الدروس والأمثلة المتقدمة.

استكشاف الدروس المتقدمة