أساسيات JavaScript

المصفوفات: الإنشاء والوصول إلى العناصر

45 دقيقة الدرس 13 من 60

ما هي المصفوفات؟

المصفوفة هي واحدة من أكثر هياكل البيانات أساسية واستخداما في جافاسكريبت. في جوهرها، المصفوفة هي مجموعة مرتبة من القيم مخزنة تحت اسم متغير واحد. بدلا من إنشاء عشرات المتغيرات المنفصلة لحفظ بيانات مترابطة، يمكنك تجميعها جميعا داخل مصفوفة واحدة. كل قيمة في المصفوفة تسمى عنصرا، ولكل عنصر موقع رقمي يسمى فهرسا. المصفوفات في جافاسكريبت مفهرسة من الصفر، مما يعني أن العنصر الأول يقع في الفهرس 0، والثاني في الفهرس 1، وهكذا.

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

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

إنشاء المصفوفات باستخدام الصيغة الحرفية

الطريقة الأكثر شيوعا والموصى بها لإنشاء مصفوفة في جافاسكريبت هي صيغة المصفوفة الحرفية. تستخدم الأقواس المربعة [] وتفصل كل عنصر بفاصلة. هذا النهج نظيف وموجز وسهل القراءة.

مثال: إنشاء المصفوفات بالصيغة الحرفية

// مصفوفة من السلاسل النصية
const fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry'];

// مصفوفة من الأرقام
const scores = [95, 87, 72, 100, 64, 88];

// مصفوفة من القيم المنطقية
const flags = [true, false, true, true, false];

// مصفوفة فارغة (ستضيف عناصر لاحقا)
const emptyList = [];

// مصفوفة بأنواع مختلطة (صالحة لكن ليست دائما موصى بها)
const mixed = ['hello', 42, true, null, undefined, { name: 'Ali' }];

console.log(fruits);   // ['apple', 'banana', 'cherry', 'date', 'elderberry']
console.log(scores);   // [95, 87, 72, 100, 64, 88]
console.log(emptyList); // []

الصيغة الحرفية مفضلة على مُنشئ Array لأنها أقصر وأوضح وتتجنب الأخطاء الدقيقة التي يمكن أن يسببها المُنشئ. يجب أن تستخدم المصفوفات الحرفية في كل الحالات تقريبا.

إنشاء المصفوفات باستخدام مُنشئ Array

توفر جافاسكريبت أيضا دالة مُنشئ Array لإنشاء المصفوفات. تستدعيها بكلمة new المفتاحية (رغم أن new اختيارية). بينما يعمل هذا النهج، فإنه يحتوي على خلل معروف يجعله أقل قابلية للتنبؤ من الصيغة الحرفية.

مثال: مُنشئ Array

// إنشاء مصفوفة بعناصر
const colors = new Array('red', 'green', 'blue');
console.log(colors); // ['red', 'green', 'blue']

// الخلل الخطير: تمرير رقم واحد
const fiveSlots = new Array(5);
console.log(fiveSlots);        // [empty x 5]
console.log(fiveSlots.length); // 5
// هذا ينشئ مصفوفة بـ 5 خانات فارغة، وليس مصفوفة تحتوي على الرقم 5!

// لإنشاء مصفوفة تحتوي على الرقم 5، استخدم الصيغة الحرفية:
const containsFive = [5];
console.log(containsFive); // [5]

// بدون كلمة 'new' المفتاحية (تعمل بنفس الطريقة)
const animals = Array('cat', 'dog', 'bird');
console.log(animals); // ['cat', 'dog', 'bird']
خطأ شائع: استخدام new Array(5) عندما تنوي إنشاء مصفوفة تحتوي على الرقم 5. هذا بدلا من ذلك ينشئ مصفوفة بـ 5 خانات فارغة. استخدم دائما الصيغة الحرفية [5] لتجنب هذا الالتباس. خلل المُنشئ تسبب في عدد لا يحصى من الأخطاء في الكود الإنتاجي.

إنشاء المصفوفات باستخدام Array.of()

تم تقديم التابع الثابت Array.of() في ES6 لحل مشكلة الغموض في مُنشئ Array. يقوم دائما بإنشاء مصفوفة تحتوي على الوسائط التي تمررها، بغض النظر عن عدد أو نوع الوسائط. إذا مررت رقما واحدا، ينشئ مصفوفة تحتوي على ذلك الرقم، وليس مصفوفة بعدد من الخانات الفارغة.

مثال: Array.of() تحل خلل المُنشئ

// Array.of() تنشئ دائما مصفوفة بالعناصر المعطاة
const singleNumber = Array.of(5);
console.log(singleNumber);        // [5]
console.log(singleNumber.length); // 1

// قارن مع المُنشئ
const constructorResult = new Array(5);
console.log(constructorResult);        // [empty x 5]
console.log(constructorResult.length); // 5

// وسائط متعددة تعمل كما هو متوقع
const values = Array.of(1, 2, 3, 4, 5);
console.log(values); // [1, 2, 3, 4, 5]

// أنواع مختلطة
const mixedOf = Array.of('hello', 42, true);
console.log(mixedOf); // ['hello', 42, true]

// مصفوفة فارغة
const emptyOf = Array.of();
console.log(emptyOf); // []
نصيحة: استخدم Array.of() عندما تحتاج لإنشاء مصفوفة برمجيا من عدد متغير من الوسائط وتريد سلوكا يمكن التنبؤ به. في معظم البرمجة اليومية، تبقى الصيغة الحرفية [] الخيار الأبسط.

إنشاء المصفوفات باستخدام Array.from()

Array.from() هي واحدة من أقوى طرق إنشاء المصفوفات في جافاسكريبت. تنشئ مصفوفة جديدة من أي كائن قابل للتكرار أو شبيه بالمصفوفة. الكائنات الشبيهة بالمصفوفة هي كائنات لها خاصية length وعناصر مفهرسة لكنها تفتقر إلى توابع المصفوفة مثل push أو map. الأمثلة الشائعة تشمل السلاسل النصية، وكائنات NodeList من DOM، وكائن arguments داخل الدوال، وكائنات Set و Map.

مثال: Array.from() مع مصادر متنوعة

// من سلسلة نصية (كل حرف يصبح عنصرا)
const letters = Array.from('Hello');
console.log(letters); // ['H', 'e', 'l', 'l', 'o']

// من Set (يزيل التكرارات تلقائيا)
const uniqueNumbers = new Set([1, 2, 2, 3, 3, 3]);
const uniqueArray = Array.from(uniqueNumbers);
console.log(uniqueArray); // [1, 2, 3]

// من Map
const userMap = new Map([['name', 'Ali'], ['age', 30]]);
const mapArray = Array.from(userMap);
console.log(mapArray); // [['name', 'Ali'], ['age', 30]]

// من كائن شبيه بالمصفوفة
const arrayLike = { 0: 'first', 1: 'second', 2: 'third', length: 3 };
const realArray = Array.from(arrayLike);
console.log(realArray); // ['first', 'second', 'third']

يقبل Array.from() أيضا وسيطا ثانيا اختياريا -- دالة ربط تحول كل عنصر أثناء إضافته إلى المصفوفة الجديدة. هذا مفيد للغاية لتوليد التسلسلات أو تحويل البيانات في خطوة واحدة.

مثال: Array.from() مع دالة ربط

// توليد مصفوفة أرقام من 1 إلى 10
const oneToTen = Array.from({ length: 10 }, (_, index) => index + 1);
console.log(oneToTen); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// توليد مصفوفة من القيم المربعة
const squares = Array.from({ length: 5 }, (_, i) => (i + 1) ** 2);
console.log(squares); // [1, 4, 9, 16, 25]

// تحويل سلسلة نصية إلى أحرف كبيرة
const upperLetters = Array.from('hello', char => char.toUpperCase());
console.log(upperLetters); // ['H', 'E', 'L', 'L', 'O']

// توليد مصفوفة من الكائنات
const users = Array.from({ length: 3 }, (_, i) => ({
    id: i + 1,
    name: `User ${i + 1}`,
    active: true
}));
console.log(users);
// [{id:1, name:'User 1', active:true}, {id:2, name:'User 2', active:true}, ...]
ملاحظة: الشرطة السفلية _ في دالة الربط هي اصطلاح شائع لمعامل لا تستخدمه. الوسيط الأول هو العنصر الحالي (وهو undefined عند الإنشاء من { length: N })، والثاني هو الفهرس.

الوصول إلى العناصر بالفهرس

تصل إلى العناصر الفردية في مصفوفة باستخدام صيغة الأقواس مع فهرس العنصر. تذكر أن مصفوفات جافاسكريبت مفهرسة من الصفر: العنصر الأول في الفهرس 0، والثاني في الفهرس 1، وهكذا. محاولة الوصول إلى فهرس غير موجود تُرجع undefined بدلا من إلقاء خطأ.

مثال: الوصول إلى العناصر بالفهرس

const planets = ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter'];

// الوصول إلى عناصر فردية
console.log(planets[0]); // 'Mercury' (العنصر الأول)
console.log(planets[1]); // 'Venus'   (العنصر الثاني)
console.log(planets[2]); // 'Earth'   (العنصر الثالث)
console.log(planets[4]); // 'Jupiter' (العنصر الخامس والأخير)

// الوصول إلى العنصر الأخير باستخدام length
console.log(planets[planets.length - 1]); // 'Jupiter'

// الوصول إلى فهرس غير موجود
console.log(planets[10]); // undefined (لا يُلقى خطأ)
console.log(planets[-1]); // undefined (الفهارس السلبية لا تعمل مع الأقواس)

// استخدام متغير كفهرس
const index = 3;
console.log(planets[index]); // 'Mars'

الفهرسة السلبية مع تابع at()

قدم ES2022 تابع at()، الذي يوفر طريقة أنظف للوصول إلى العناصر باستخدام فهارس إيجابية وسلبية. مع الفهارس السلبية، at(-1) يُرجع العنصر الأخير، و at(-2) يُرجع ما قبل الأخير، وهكذا. هذا يلغي الحاجة لنمط array[array.length - 1].

مثال: تابع at()

const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'purple'];

// فهارس إيجابية (نفس صيغة الأقواس)
console.log(colors.at(0));  // 'red'
console.log(colors.at(2));  // 'yellow'

// فهارس سلبية (العد من النهاية)
console.log(colors.at(-1)); // 'purple' (العنصر الأخير)
console.log(colors.at(-2)); // 'blue'   (ما قبل الأخير)
console.log(colors.at(-3)); // 'green'  (ثالث عنصر من النهاية)

// قارن مع النهج القديم
console.log(colors[colors.length - 1]); // 'purple' (الطريقة القديمة)
console.log(colors.at(-1));             // 'purple' (الطريقة الجديدة -- أنظف بكثير)

// مفيد في إرجاع الدوال
function getLastItem(arr) {
    return arr.at(-1);
}
console.log(getLastItem([10, 20, 30])); // 30
نصيحة: تابع at() مدعوم في جميع المتصفحات الحديثة و Node.js 16.6+. استخدمه كلما احتجت للوصول إلى عناصر من نهاية المصفوفة. يجعل كودك أكثر قابلية للقراءة وأقل عرضة للأخطاء من نمط length - 1.

خاصية length

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

مثال: العمل مع خاصية length

const items = ['a', 'b', 'c', 'd', 'e'];
console.log(items.length); // 5

// الطول هو دائما واحد أكثر من أعلى فهرس
console.log(items[items.length - 1]); // 'e'

// تعيين الطول لقيمة أصغر يقطع المصفوفة
items.length = 3;
console.log(items); // ['a', 'b', 'c'] -- تمت إزالة 'd' و 'e' نهائيا

// تعيين الطول لقيمة أكبر ينشئ خانات فارغة
items.length = 6;
console.log(items); // ['a', 'b', 'c', empty x 3]

// تفريغ مصفوفة بتعيين الطول إلى 0
const numbers = [1, 2, 3, 4, 5];
numbers.length = 0;
console.log(numbers); // []

// التحقق مما إذا كانت المصفوفة فارغة
const tasks = [];
if (tasks.length === 0) {
    console.log('لا توجد مهام لعرضها.');
}
تحذير: اقتطاع مصفوفة بتعيين length لقيمة أصغر يزيل تلك العناصر نهائيا. لا يمكن التراجع عن ذلك. استخدم هذه التقنية عمدا، وليس عن طريق الخطأ. إذا كنت بحاجة للاحتفاظ بالبيانات الأصلية، أنشئ نسخة أولا باستخدام slice() أو عامل الانتشار.

تعديل العناصر

يمكنك تغيير أي عنصر في مصفوفة بتعيين قيمة جديدة لفهرسه. يمكنك أيضا إضافة عناصر جديدة بالتعيين لفهرس يتجاوز الطول الحالي للمصفوفة. كن حذرا مع الفجوات -- التعيين لفهرس بعيد جدا عن الطول الحالي للمصفوفة ينشئ مصفوفات متفرقة مع خانات فارغة بينها.

مثال: تعديل عناصر المصفوفة

const languages = ['Python', 'JavaScript', 'Java', 'C++'];

// تعديل عنصر موجود
languages[1] = 'TypeScript';
console.log(languages); // ['Python', 'TypeScript', 'Java', 'C++']

// إضافة عنصر جديد في الفهرس التالي
languages[4] = 'Rust';
console.log(languages); // ['Python', 'TypeScript', 'Java', 'C++', 'Rust']

// إنشاء مصفوفة متفرقة (تجنب هذا!)
languages[10] = 'Go';
console.log(languages);
// ['Python', 'TypeScript', 'Java', 'C++', 'Rust', empty x 5, 'Go']
console.log(languages.length); // 11

// التحقق من الخانات الفارغة
console.log(languages[7]); // undefined (خانة فارغة)
console.log(7 in languages); // false (لا يوجد عنصر فعلا في الفهرس 7)

// قارن مع قيمة undefined حقيقية
languages[8] = undefined;
console.log(languages[8]); // undefined (لكن العنصر موجود)
console.log(8 in languages); // true
ملاحظة: المصفوفات المتفرقة (المصفوفات ذات الفجوات) يمكن أن تسبب سلوكا غير متوقع مع توابع مثل forEach و map و filter لأنها قد تتخطى الخانات الفارغة. تجنب إنشاء مصفوفات متفرقة في كودك.

المصفوفات متعددة الأبعاد

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

مثال: المصفوفات ثنائية الأبعاد

// شبكة 3×3 (لوحة إكس-أو)
const board = [
    ['X', 'O', 'X'],
    ['O', 'X', 'O'],
    ['X', ' ', 'O']
];

// الوصول إلى خلايا فردية
console.log(board[0][0]); // 'X' (الصف الأول، العمود الأول)
console.log(board[1][1]); // 'X' (الصف الثاني، العمود الثاني -- المركز)
console.log(board[2][1]); // ' ' (الصف الثالث، العمود الثاني)

// تعديل خلية
board[2][1] = 'X';
console.log(board[2]); // ['X', 'X', 'O']

// جدول درجات الطلاب
const grades = [
    ['Ali',   95, 88, 92],
    ['Sara',  78, 85, 90],
    ['Omar',  100, 97, 95]
];

// الوصول إلى الدرجة الثانية لسارة
console.log(grades[1][2]); // 85

// التكرار عبر جميع الدرجات
for (let row = 0; row < grades.length; row++) {
    const name = grades[row][0];
    const avg = (grades[row][1] + grades[row][2] + grades[row][3]) / 3;
    console.log(`${name}: المعدل = ${avg.toFixed(1)}`);
}
// Ali: المعدل = 91.7
// Sara: المعدل = 84.3
// Omar: المعدل = 97.3

مثال: مصفوفة ثلاثية الأبعاد

// مصفوفة ثلاثية الأبعاد تمثل مبنى بطوابق وغرف وأغراض
const building = [
    // الطابق 0
    [
        ['desk', 'chair'],      // الغرفة 0
        ['sofa', 'table', 'lamp'] // الغرفة 1
    ],
    // الطابق 1
    [
        ['bed', 'wardrobe'],    // الغرفة 0
        ['bookshelf', 'plant']  // الغرفة 1
    ]
];

// الوصول: الطابق 1، الغرفة 0، الغرض 1
console.log(building[1][0][1]); // 'wardrobe'

// الوصول: الطابق 0، الغرفة 1، الغرض 2
console.log(building[0][1][2]); // 'lamp'

التحقق مما إذا كانت القيمة مصفوفة: Array.isArray()

عامل typeof في جافاسكريبت يُرجع 'object' للمصفوفات، وهو غير مفيد عندما تحتاج للتمييز بين كائن عادي ومصفوفة. التابع الثابت Array.isArray() يحدد بشكل موثوق ما إذا كانت القيمة مصفوفة. هذا ضروري لكتابة دوال قوية تحتاج للتعامل مع أنواع مدخلات مختلفة.

مثال: Array.isArray() في العمل

// المشكلة مع typeof
console.log(typeof [1, 2, 3]);     // 'object' (غير مفيد!)
console.log(typeof { a: 1 });      // 'object' (نفس النتيجة!)

// Array.isArray() تحل هذه المشكلة
console.log(Array.isArray([1, 2, 3]));    // true
console.log(Array.isArray([]));            // true
console.log(Array.isArray('hello'));       // false
console.log(Array.isArray({ a: 1 }));     // false
console.log(Array.isArray(123));           // false
console.log(Array.isArray(null));          // false
console.log(Array.isArray(undefined));     // false

// استخدام عملي: دالة تقبل قيمة واحدة أو مصفوفة
function processInput(input) {
    const items = Array.isArray(input) ? input : [input];
    // الآن 'items' دائما مصفوفة، بغض النظر عن نوع المدخل
    items.forEach(item => console.log(`معالجة: ${item}`));
}

processInput('قيمة واحدة');
// معالجة: قيمة واحدة

processInput(['الأول', 'الثاني', 'الثالث']);
// معالجة: الأول
// معالجة: الثاني
// معالجة: الثالث
ملاحظة: عامل instanceof (value instanceof Array) يعمل أيضا في معظم الحالات، لكنه قد يفشل عند التعامل مع مصفوفات من إطارات أو نوافذ مختلفة في المتصفح. Array.isArray() هو الخيار الموثوق عالميا.

تفكيك المصفوفات

التفكيك هو صيغة جافاسكريبت حديثة (ES6) تسمح لك بفك قيم من المصفوفات إلى متغيرات مميزة. بدلا من الوصول إلى العناصر واحدا تلو الآخر بصيغة الأقواس، يمكنك استخراج قيم متعددة في جملة واحدة أنيقة. التفكيك يجعل كودك أقصر وأكثر تعبيرا.

مثال: تفكيك المصفوفات الأساسي

const coordinates = [40.7128, -74.0060, 'New York'];

// بدون تفكيك
const lat = coordinates[0];
const lng = coordinates[1];
const city = coordinates[2];

// مع التفكيك (أنظف بكثير)
const [latitude, longitude, cityName] = coordinates;
console.log(latitude);  // 40.7128
console.log(longitude); // -74.0060
console.log(cityName);  // 'New York'

// تخطي العناصر بالفواصل
const colors = ['red', 'green', 'blue', 'yellow', 'purple'];
const [first, , third] = colors;
console.log(first); // 'red'
console.log(third); // 'blue' (تم تخطي green)

// القيم الافتراضية
const [a, b, c, d = 'default'] = [1, 2, 3];
console.log(d); // 'default' (لا يوجد عنصر رابع، لذا تُستخدم القيمة الافتراضية)

// نمط الباقي: جمع العناصر المتبقية
const [head, ...tail] = [10, 20, 30, 40, 50];
console.log(head); // 10
console.log(tail); // [20, 30, 40, 50]

// تبديل المتغيرات بدون متغير مؤقت
let x = 'first';
let y = 'second';
[x, y] = [y, x];
console.log(x); // 'second'
console.log(y); // 'first'

مثال: التفكيك مع الدوال

// دالة تُرجع قيما متعددة كمصفوفة
function getMinMax(numbers) {
    const min = Math.min(...numbers);
    const max = Math.max(...numbers);
    return [min, max];
}

const [minimum, maximum] = getMinMax([5, 2, 9, 1, 7]);
console.log(minimum); // 1
console.log(maximum); // 9

// التفكيك في حلقة for...of
const entries = [['name', 'Ali'], ['age', 25], ['city', 'Dubai']];
for (const [key, value] of entries) {
    console.log(`${key}: ${value}`);
}
// name: Ali
// age: 25
// city: Dubai

// التفكيك المتداخل
const matrix = [[1, 2], [3, 4]];
const [[a1, a2], [b1, b2]] = matrix;
console.log(a1, a2, b1, b2); // 1 2 3 4

عامل الانتشار مع المصفوفات

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

مثال: أنماط عامل الانتشار

// نسخ مصفوفة (نسخة سطحية)
const original = [1, 2, 3, 4, 5];
const copy = [...original];
console.log(copy);            // [1, 2, 3, 4, 5]
console.log(copy === original); // false (مرجع مختلف)

// دمج (ربط) المصفوفات
const frontend = ['HTML', 'CSS', 'JavaScript'];
const backend = ['Node.js', 'Python', 'Java'];
const fullstack = [...frontend, ...backend];
console.log(fullstack);
// ['HTML', 'CSS', 'JavaScript', 'Node.js', 'Python', 'Java']

// إضافة عناصر في مواقع محددة
const withMiddle = [...frontend, 'React', ...backend];
console.log(withMiddle);
// ['HTML', 'CSS', 'JavaScript', 'React', 'Node.js', 'Python', 'Java']

// الانتشار في وسائط الدوال
const numbers = [5, 2, 9, 1, 7];
console.log(Math.max(...numbers)); // 9
console.log(Math.min(...numbers)); // 1

// تحويل سلسلة نصية إلى مصفوفة أحرف
const chars = [...'Hello'];
console.log(chars); // ['H', 'e', 'l', 'l', 'o']

// إزالة التكرارات بالدمج مع Set
const withDupes = [1, 2, 2, 3, 3, 3, 4];
const unique = [...new Set(withDupes)];
console.log(unique); // [1, 2, 3, 4]
مهم: عامل الانتشار ينشئ نسخة سطحية. إذا كانت مصفوفتك تحتوي على كائنات أو مصفوفات متداخلة، فإن تلك المراجع الداخلية مشتركة وليست مكررة. تعديل كائن متداخل في النسخة سيعدله أيضا في الأصل. للنسخ العميق، استخدم structuredClone() أو مكتبة مثل Lodash.

مثال: مشكلة النسخة السطحية

const users = [
    { name: 'Ali', age: 25 },
    { name: 'Sara', age: 30 }
];

const usersCopy = [...users];

// تعديل كائن متداخل يؤثر على كلتا المصفوفتين!
usersCopy[0].age = 99;
console.log(users[0].age);     // 99 (تغيرت في الأصل أيضا!)
console.log(usersCopy[0].age); // 99

// للحصول على نسخة عميقة حقيقية، استخدم structuredClone()
const usersDeep = structuredClone(users);
usersDeep[0].age = 50;
console.log(users[0].age);     // 99 (لم تتغير هذه المرة)
console.log(usersDeep[0].age); // 50

أمثلة من العالم الحقيقي

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

مثال: إدارة قائمة تشغيل

// إنشاء قائمة تشغيل موسيقية
const playlist = [
    { title: 'Bohemian Rhapsody', artist: 'Queen', duration: 355 },
    { title: 'Stairway to Heaven', artist: 'Led Zeppelin', duration: 482 },
    { title: 'Hotel California', artist: 'Eagles', duration: 391 },
    { title: 'Imagine', artist: 'John Lennon', duration: 183 }
];

// الوصول إلى الأغنية الأولى والأخيرة
const firstSong = playlist[0];
const lastSong = playlist.at(-1);
console.log(`يتم التشغيل الآن: ${firstSong.title} لـ ${firstSong.artist}`);
console.log(`الأخيرة: ${lastSong.title} لـ ${lastSong.artist}`);

// حساب المدة الإجمالية لقائمة التشغيل
let totalSeconds = 0;
for (let i = 0; i < playlist.length; i++) {
    totalSeconds += playlist[i].duration;
}
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
console.log(`المدة الإجمالية لقائمة التشغيل: ${minutes}د ${seconds}ث`);

// تفكيك خصائص الأغنية
const [{ title: firstTitle }, , { title: thirdTitle }] = playlist;
console.log(firstTitle); // 'Bohemian Rhapsody'
console.log(thirdTitle); // 'Hotel California'

مثال: معالجة نتائج استطلاع

// ردود الاستطلاع كمصفوفة ثنائية الأبعاد [معرف_المستجيب، التقييم، التعليق]
const responses = [
    [1, 5, 'خدمة ممتازة'],
    [2, 4, 'جيدة جدا'],
    [3, 3, 'تجربة متوسطة'],
    [4, 5, 'رائعة!'],
    [5, 2, 'تحتاج تحسين'],
    [6, 4, 'جيدة بشكل عام']
];

// حساب متوسط التقييم
let totalRating = 0;
for (let i = 0; i < responses.length; i++) {
    totalRating += responses[i][1];
}
const averageRating = totalRating / responses.length;
console.log(`متوسط التقييم: ${averageRating.toFixed(1)} / 5`);
// متوسط التقييم: 3.8 / 5

// استخراج جميع التقييمات باستخدام التفكيك في حلقة
const ratings = [];
for (const [id, rating, comment] of responses) {
    ratings.push(rating);
    if (rating <= 2) {
        console.log(`تنبيه: تقييم منخفض (${rating}) من المستجيب ${id}: "${comment}"`);
    }
}

// التحقق مما إذا كان لدينا ردود كافية
if (Array.isArray(responses) && responses.length >= 5) {
    console.log('بيانات كافية للتحليل.');
}

// إنشاء نسخة للتحليل دون تعديل الأصل
const analysisCopy = [...responses];
console.log(analysisCopy.length); // 6

مثال: بناء مولد لوحة ألوان

// توليد لوحة ألوان
function generatePalette(baseColors, variations) {
    if (!Array.isArray(baseColors)) {
        baseColors = [baseColors]; // تطبيع إلى مصفوفة
    }

    const palette = [];
    for (const color of baseColors) {
        for (let i = 0; i < variations; i++) {
            const lightness = 20 + (i * (60 / variations));
            palette.push(`hsl(${color}, 70%, ${lightness.toFixed(0)}%)`);
        }
    }
    return palette;
}

// توليد لوحات لدرجات ألوان مختلفة
const warmPalette = generatePalette([0, 30, 60], 4);
console.log(warmPalette);
// ['hsl(0, 70%, 20%)', 'hsl(0, 70%, 35%)', ...]

// دمج اللوحات باستخدام الانتشار
const coolHues = [180, 210, 240];
const coolPalette = generatePalette(coolHues, 3);
const fullPalette = [...warmPalette, ...coolPalette];
console.log(`إجمالي الألوان في اللوحة: ${fullPalette.length}`);

// الحصول على أول 3 ألوان والبقية
const [primary, secondary, accent, ...rest] = fullPalette;
console.log(`الأساسي: ${primary}`);
console.log(`الثانوي: ${secondary}`);
console.log(`التمييز: ${accent}`);
console.log(`الألوان المتبقية: ${rest.length}`);

تمرين عملي

أنشئ تطبيق سجل درجات الطلاب. ابدأ بإنشاء مصفوفة من 5 كائنات طلاب على الأقل، كل منها يحتوي على اسم، ومصفوفة من درجات الاختبارات، ومستوى دراسي. ثم اكتب كودا لـ: (1) الوصول إلى درجة الاختبار الثانية للطالب الثالث باستخدام صيغة الأقواس. (2) استخدام at(-1) للحصول على آخر طالب. (3) استخدام Array.isArray() للتحقق من أن خاصية الدرجات هي مصفوفة. (4) استخدام التفكيك لاستخراج اسم الطالب الأول ودرجاته إلى متغيرات منفصلة. (5) استخدام عامل الانتشار لإنشاء مصفوفة مدمجة من جميع درجات الطلاب. (6) إنشاء مصفوفة ثنائية الأبعاد تمثل مخطط جلوس بـ 3 صفوف و 4 مقاعد لكل صف، ثم الوصول إلى مقعد محدد. (7) استخدام Array.from() لتوليد مصفوفة من 10 درجات اختبار عشوائية بين 60 و 100. اختبر كل خطوة وتحقق من المخرجات في وحدة تحكم المتصفح.

ES
Edrees Salih
منذ 22 ساعة

We are still cooking the magic in the way!