الدليل العملي لمصفوفات JavaScript: شرح أشهر الدوال مع أمثلة واضحة

دقائق القراءة: 9

مقدمة إلى مصفوفات JavaScript

تُعدّ المصفوفة Array من أهم هياكل البيانات في البرمجة، لأنها تتيح تخزين مجموعة من العناصر داخل متغير واحد بطريقة منظّمة وسهلة المعالجة. في لغة JavaScript تُستخدم المصفوفات بكثرة عند التعامل مع القوائم، والبيانات الديناميكية، ونتائج API، وبُنى الواجهات التفاعلية.

في هذا الدليل ستتعرّف إلى مفهوم المصفوفات، وكيفية إنشائها، والوصول إلى عناصرها، وإضافة البيانات وحذفها، ثم الانتقال إلى أشهر دوال المصفوفات مثل map() وfilter() وreduce() مع أمثلة عملية تساعدك على الفهم والتطبيق.

غلاف دليل مصفوفات جافاسكربت وشرح دوال JavaScript Array Methods

ما هي المصفوفة في JavaScript؟

المصفوفة هي مجموعة مرتبة من العناصر، وتُكتب بين قوسين مربعين []، مع الفصل بين العناصر بفاصلة ,. وتمتاز مصفوفات JavaScript بمرونة عالية، إذ يمكن أن تحتوي على أنواع بيانات مختلفة داخل المصفوفة نفسها.

مثال على مصفوفة تضم أرقاماً وقِيَماً منطقية ونصوصاً وكائناً:

const mixedTypedArray = [100, true, 'freeCodeCamp', {}];

لكل عنصر داخل المصفوفة موضع يُعرف باسم index، ويبدأ العد دائماً من 0. هذا يعني أن أول عنصر يقع عند index 0، والثاني عند index 1، وهكذا.

أما عدد العناصر فيُعرف عبر الخاصية length. ومن المهم معرفة أن مصفوفات JavaScript ليست ثابتة الطول، بل يمكن تعديلها أثناء تشغيل البرنامج.

كيفية إنشاء مصفوفة في JavaScript

الطريقة المباشرة باستخدام الأقواس المربعة

هذه هي الطريقة الأكثر شيوعاً ووضوحاً:

const salad = ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑'];

استخدام الباني Array

يمكن أيضاً إنشاء المصفوفة عبر الباني Array:

const salad = new Array('🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑');

لكن انتبه إلى هذا الفرق المهم:

  • new Array(2) ينشئ مصفوفة طولها 2، لكن عناصرها غير معرّفة.
  • new Array(1, 2) ينشئ مصفوفة تحتوي فعلياً على العنصرين 1 و2.

كما توجد طرق حديثة ومفيدة مثل Array.of() وArray.from()، بالإضافة إلى عامل الانتشار ....

الوصول إلى عناصر المصفوفة

يمكنك الوصول إلى أي عنصر باستخدام الفهرس index داخل الأقواس المربعة:

const element = array[index];

مثال عملي:

const salad = ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑'];
salad[0]; // '🍅'
salad[2]; // '🥦'
salad[5]; // '🥕'

الوصول إلى العناصر من نهاية المصفوفة

قبل توفر بعض الأساليب الحديثة، كان الوصول إلى آخر عنصر يعتمد غالباً على الخاصية length:

const salad = ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑'];
const len = salad.length;

salad[len - 1]; // '🥑'
salad[len - 3]; // '🌽'

التكرار على عناصر المصفوفة

يمكنك استعراض العناصر باستخدام حلقة for أو forEach() أو غيرهما:

const salad = ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑'];

for (let i = 0; i < salad.length; i++) {
  console.log(`Element at index ${i} is ${salad[i]}`);
}

مخرجات التكرار على عناصر مصفوفة في جافاسكربت باستخدام for loop

إضافة عناصر إلى المصفوفة

الإضافة في نهاية المصفوفة باستخدام push()

const salad = ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑'];
salad.push('🥜');

ستصبح المصفوفة كالتالي:

["🍅", "🍄", "🥦", "🥒", "🌽", "🥕", "🥑", "🥜"]

الإضافة في بداية المصفوفة باستخدام unshift()

const salad = ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑'];
salad.unshift('🥜');

والنتيجة:

["🥜", "🍅", "🍄", "🥦", "🥒", "🌽", "🥕", "🥑"]

حذف عناصر من المصفوفة

حذف آخر عنصر باستخدام pop()

const salad = ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑'];

salad.pop(); // 🥑
console.log(salad); // ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕']

حذف أول عنصر باستخدام shift()

const salad = ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑'];

salad.shift(); // 🍅
console.log(salad); // ['🍄', '🥦', '🥒', '🌽', '🥕', '🥑']

نسخ المصفوفة واستنساخها

النسخ باستخدام slice()

إذا أردت إنشاء نسخة سطحية shallow copy من المصفوفة دون تعديل الأصل، فاستخدم slice():

const salad = ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑'];
const saladCopy = salad.slice();

console.log(saladCopy);
// ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑']

salad === saladCopy; // false

النسخ باستخدام عامل الانتشار ...

const salad = ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑'];
const saladCloned = [...salad];

console.log(saladCloned);
// ["🍅", "🍄", "🥦", "🥒", "🌽", "🥕", "🥑"]

هذه الطريقة عملية جداً، لكنها أيضاً تُنتج نسخة سطحية فقط.

التحقق مما إذا كانت القيمة مصفوفة

قد تصادف بيانات غير واضحة المصدر، وهنا يفيد استخدام Array.isArray():

Array.isArray(['🍅', '🍄', '🥦']); // true
Array.isArray('🍅'); // false
Array.isArray({ tomato: '🍅' }); // false
Array.isArray([]); // true

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

وفرت ES6 صيغة مريحة لاستخراج قيم متعددة من المصفوفة وإسنادها مباشرة إلى متغيرات.

let [tomato, mushroom, carrot] = ['🍅', '🍄', '🥕'];
console.log(tomato, mushroom, carrot); // 🍅 🍄 🥕

وبدون هذا الأسلوب ستحتاج إلى كتابة أكثر:

let vegetables = ['🍅', '🍄', '🥕'];
let tomato = vegetables[0];
let mushroom = vegetables[1];
let carrot = vegetables[2];

تعيين قيمة افتراضية

let [tomato, mushroom = '🍄'] = ['🍅'];

console.log(tomato);   // '🍅'
console.log(mushroom); // '🍄'

تخطي عنصر غير مطلوب

let [tomato, , carrot] = ['🍅', '🍄', '🥕'];

console.log(tomato); // '🍅'
console.log(carrot); // '🥕'

تفكيك المصفوفات المتداخلة

let fruits = ['🍈', '🍍', '🍌', '🍉', ['🍅', '🍄', '🥕']];

للوصول إلى العنصر '🥕' يمكن كتابة:

fruits[4][2]; // returns '🥕'

أو باستخدام التفكيك:

let [,,,, [,, carrot]] = ['🍈', '🍍', '🍌', '🍉', ['🍅', '🍄', '🥕']];

عامل الانتشار Spread ومعامل الباقي Rest

استخدام Rest Parameter

عندما يظهر ... في الجهة اليسرى من التفكيك، فإنه يجمع العناصر المتبقية في مصفوفة جديدة:

const [tomato, mushroom, ...rest] = ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑'];

console.log(tomato);   // '🍅'
console.log(mushroom); // '🍄'
console.log(rest);     // ["🥦", "🥒", "🌽", "🥕", "🥑"]

استخدام Spread Operator

عندما يظهر ... في الجهة اليمنى، فإنه ينشر عناصر المصفوفة:

const salad = ['🍅', '🍄', '🥦', '🥒', '🌽', '🥕', '🥑'];
const saladCloned = [...salad];

salad === saladCloned; // false

تبديل القيم بسهولة

let first = '😔';
let second = '🙂';

[first, second] = [second, first];

console.log(first);  // '🙂'
console.log(second); // '😔'

دمج مصفوفتين أو أكثر

const emotion = ['🙂', '😔'];
const veggies = ['🥦', '🥒', '🌽', '🥕'];

const emotionalVeggies = [...emotion, ...veggies];
console.log(emotionalVeggies);

ملخص سريع لأشهر الخصائص والدوال الأساسية

  • push(): إضافة عنصر إلى نهاية المصفوفة.
  • unshift(): إضافة عنصر إلى بداية المصفوفة.
  • pop(): حذف آخر عنصر.
  • shift(): حذف أول عنصر.
  • slice(): إنشاء نسخة سطحية من المصفوفة.
  • Array.isArray(): التحقق من كون القيمة مصفوفة.
  • length: معرفة عدد العناصر.

دوال المصفوفات المهمة في JavaScript

الدالة concat()

تُستخدم لدمج مصفوفتين أو أكثر دون تعديل المصفوفات الأصلية:

const first = [1, 2, 3];
const second = [4, 5, 6];
const merged = first.concat(second);

console.log(merged); // [1, 2, 3, 4, 5, 6]
const third = [7, 8, 9];
const mergedAll = first.concat(second, third);

console.log(mergedAll); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

الدالة join()

تحوّل عناصر المصفوفة إلى سلسلة نصية واحدة باستخدام فاصل تحدده أنت:

const emotions = ['🙂', '😍', '🙄', '😟'];
const joined = emotions.join();

console.log(joined); // "🙂,😍,🙄,😟"
const customJoined = emotions.join('<=>');
console.log(customJoined); // "🙂<=>😍<=>🙄<=>😟"
[].join(); // ""

الدالة fill()

تملأ المصفوفة بقيمة ثابتة، مع إمكانية تحديد بداية ونهاية التعديل:

const colors = ['red', 'blue', 'green'];
colors.fill('pink');

console.log(colors); // ["pink", "pink", "pink"]
const moreColors = ['red', 'blue', 'green'];
moreColors.fill('pink', 1, 3);

console.log(moreColors); // ["red", "pink", "pink"]

الدالة includes()

تتحقق مما إذا كانت المصفوفة تحتوي على عنصر معين:

const names = ['tom', 'alex', 'bob', 'john'];

names.includes('tom');  // true
names.includes('july'); // false

الدالتان indexOf() وlastIndexOf()

تحددان موضع العنصر داخل المصفوفة:

const names = ['tom', 'alex', 'bob', 'john'];

names.indexOf('alex'); // 1
names.indexOf('rob');  // -1
const repeatedNames = ['tom', 'alex', 'bob', 'tom'];

repeatedNames.indexOf('tom');     // 0
repeatedNames.lastIndexOf('tom'); // 3

الدالة reverse()

تعكس ترتيب العناصر وتعدّل المصفوفة الأصلية:

const names = ['tom', 'alex', 'bob'];

names.reverse(); // ["bob", "alex", "tom"]

الدالة sort()

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

const names = ['tom', 'alex', 'bob'];
names.sort();

// ["alex", "bob", "tom"]

أما مع الأرقام:

const numbers = [23, 5, 100, 56, 9, 13, 37, 10, 1];
numbers.sort();

// [1, 10, 100, 13, 23, 37, 5, 56, 9]

هذا السلوك يحدث لأن الترتيب الافتراضي يعتمد على مقارنة النصوص. والحل يكون بتمرير دالة مقارنة:

function ascendingComp(a, b) {
  return a - b;
}

numbers.sort(ascendingComp);
// [1, 5, 9, 10, 13, 23, 37, 56, 100]
numbers.sort((a, b) => b - a);
// ترتيب تنازلي

الدالة splice()

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

إضافة عنصر

const names = ['tom', 'alex', 'bob'];

names.splice(1, 0, 'zack');
console.log(names); // ["tom", "zack", "alex", "bob"]

حذف عنصر واستبداله

const names = ['tom', 'alex', 'bob'];
const deleted = names.splice(2, 1, 'zack');

console.log(deleted); // ["bob"]
console.log(names);   // ["tom", "alex", "zack"]

الدوال الثابتة للمصفوفات Static Array Methods

الدالة Array.from()

من المشكلات الشائعة في الويب التعامل مع كائنات تشبه المصفوفات لكنها ليست مصفوفات فعلية، مثل HTMLCollection. لهذا السبب نستخدم Array.from() لتحويلها إلى مصفوفة حقيقية.

مثال HTML:

<div id="main">
  <ul>
    <ol type="1">
      <li>...</li>
      <li>...</li>
      <li>...</li>
      <li>...</li>
      <li>...</li>
      <li>...</li>
      <li>...</li>
      <li>...</li>
      <li>...</li>
      <li>...</li>
    </ol>
  </ul>
</div>

عند تنفيذ:

document.getElementsByTagName('li');

ستحصل على HTMLCollection:

نتيجة getElementsByTagName على شكل HTMLCollection في جافاسكربت

وإذا حاولت استخدام forEach() مباشرة فقد يظهر خطأ:

document.getElementsByTagName('li').forEach(() => {
  // Do something here..
});

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

الحل:

const collection = Array.from(document.getElementsByTagName('li'));

الآن أصبح collection مصفوفة فعلية:

تحويل HTMLCollection إلى Array باستخدام Array.from في جافاسكربت

الدالة Array.of()

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

Array.of(2, false, 'test', { name: 'Alex' });

مثال على استخدام Array.of لإنشاء مصفوفة جديدة في جافاسكربت

دوال التكرار على المصفوفات Array Iterator Methods

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

let students = [
  {
    id: 1,
    f_name: 'Alex',
    l_name: 'B',
    gender: 'M',
    married: false,
    age: 22,
    paid: 250,
    courses: ['JavaScript', 'React']
  },
  {
    id: 2,
    f_name: 'Ibrahim',
    l_name: 'M',
    gender: 'M',
    married: true,
    age: 32,
    paid: 150,
    courses: ['JavaScript', 'PWA']
  },
  {
    id: 3,
    f_name: 'Rubi',
    l_name: 'S',
    gender: 'F',
    married: false,
    age: 27,
    paid: 350,
    courses: ['Blogging', 'React', 'UX']
  },
  {
    id: 4,
    f_name: 'Zack',
    l_name: 'F',
    gender: 'M',
    married: true,
    age: 36,
    paid: 250,
    courses: ['Git', 'React', 'Branding']
  }
];

الدالة filter()

تنشئ مصفوفة جديدة تضم العناصر التي تحقق شرطاً معيناً:

const femaleStudents = students.filter((element, index) => {
  return element.gender === 'F';
});

console.log(femaleStudents);

مثال على استخدام filter لاستخراج الطالبات من مصفوفة كائنات في جافاسكربت

الدالة map()

تُستخدم لإنشاء مصفوفة جديدة بعد تطبيق تحويل على كل عنصر:

const fullNames = students.map((element, index) => {
  return {
    fullName: element['f_name'] + ' ' + element['l_name']
  };
});

console.log(fullNames);

مثال على استخدام map لإنشاء مصفوفة أسماء كاملة من بيانات الطلاب في جافاسكربت

الدالة reduce()

تطبّق دالة تراكمية على عناصر المصفوفة لإنتاج قيمة واحدة نهائية:

const total = students.reduce((accumulator, student, currentIndex, array) => {
  accumulator = accumulator + student.paid;
  return accumulator;
}, 0);

console.log(total); // 1000

تُعد reduce() ممتازة لحساب الإجماليات، وبناء الكائنات، وتجميع النتائج المعقدة.

الدالة some()

تُرجع قيمة منطقية true إذا حقق عنصر واحد على الأقل الشرط:

let hasStudentBelow30 = students.some((element, index) => {
  return element.age < 30;
});

console.log(hasStudentBelow30); // true

الدالتان find() وfindIndex()

تعيد find() أول عنصر يطابق الشرط، بينما تعيد findIndex() موضعه:

const student = students.find((element, index) => {
  return element.age < 30;
});

console.log(student);

مثال على استخدام find للعثور على أول طالب عمره أقل من 30 في جافاسكربت

الدالة every()

تتحقق مما إذا كانت جميع عناصر المصفوفة تستوفي الشرط:

const atLeastTwoCourses = students.every((elements, index) => {
  return elements.courses.length >= 2;
});

console.log(atLeastTwoCourses); // true

الدالة at() للوصول المرن إلى العناصر

أصبحت الدالة at() من الإضافات المفيدة في JavaScript، لأنها تسمح بالوصول إلى العناصر عبر فهارس موجبة أو سالبة، وهو ما يجعل قراءة الكود أوضح عند التعامل مع آخر عناصر المصفوفة.

const junkFoodILove = ['🥖', '🍔', '🍟', '🍕', '🌭', '🥪', '🌮', '🍿'];

junkFoodILove.at(0);   // 🥖
junkFoodILove.at(3);   // 🍕
junkFoodILove.at(-1);  // 🍿
junkFoodILove.at(-5);  // 🍕
junkFoodILove.at(-8);  // 🥖
junkFoodILove.at(10);  // undefined

عرض توضيحي لاستخدام الدالة at للوصول إلى عناصر المصفوفة بفهرس سالب في جافاسكربت

أفضل ممارسات عند التعامل مع المصفوفات

  • استخدم map() عندما تريد تحويل البيانات دون تعديل الأصل.
  • استخدم filter() عند الحاجة إلى استخراج مجموعة فرعية من العناصر.
  • تجنب الاعتماد على sort() الافتراضية مع الأرقام من دون دالة مقارنة.
  • افهم الفرق بين الدوال التي تعدّل المصفوفة الأصلية مثل splice() وreverse() وsort()، والدوال غير المعدّلة مثل concat() وslice() وmap().
  • عند نسخ مصفوفة من الكائنات، تذكّر أن النسخ السطحي لا ينسخ الكائنات الداخلية بعمق.

الخلاصة التقنية

مصفوفات JavaScript ليست مجرد وسيلة لتخزين البيانات، بل هي حجر أساس في بناء المنطق البرمجي الحديث داخل الواجهات والتطبيقات. كلما أتقنت دوال مثل filter() وmap() وreduce() وsplice()، أصبحت قادراً على كتابة كود أكثر وضوحاً وكفاءة وقابلية للصيانة. ومن الناحية العملية، فإن فهم الفرق بين الدوال التي تُنشئ نسخة جديدة وتلك التي تعدّل المصفوفة الأصلية هو ما يميز المطور المتمكن عن المبتدئ.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *