Menu
العربية

حلقتا for...of و for...in في JavaScript: شرح والفرق

تعرّف على الفرق الحقيقي بين for...of و for...in في JavaScript: قيم أم مفاتيح؟ مصفوفات أم كائنات؟ ومتى تستخدم كل واحدة منهما.

حلقتان متشابهتان بالشكل، لكن كل واحدة لها مهمتها

في جافا سكريبت فيه صيغتان للحلقات شكلهما متطابق تقريبًا، لكن وظيفة كل واحدة مختلفة تمامًا. حلقة for...of تمرّ على القيم داخل أي كائن قابل للتكرار (iterable)، بينما for...in تمرّ على المفاتيح الخاصة بالكائن. الفرق بين for of و for in مجرد حرف واحد، لكن السلوك مختلف جذريًا.

وهذا المثال التالي يلخّص القصة كاملة:

index.js
Output
Click Run to see the output here.

الحلقة الأولى تطبع تفاح وموز وكرز — أي القيم. أما الثانية فتطبع 0 و1 و2 — أي المفاتيح على هيئة نصوص. اختَر الخطأ منهما وستقضي عشر دقائق تتساءل لماذا امتلأت مصفوفتك بالأرقام.

‏for...of: المرور على القيم في أي كائن قابل للتكرار

الحلقة for...of هي الخيار الذي ستلجأ إليه في معظم الأحيان. تعمل مع أي شيء تعتبره جافا سكريبت قابلاً للتكرار (iterable): المصفوفات، السلاسل النصية، Map، Set، NodeList، المولِّدات (generators)، وغيرها.

index.js
Output
Click Run to see the output here.

لا داعي للعبث بالفهارس، ولا حاجة لكتابة scores[i]. تطلب كل قيمة، فتحصل على كل قيمة مباشرة. حتى النصوص قابلة للتكرار في جافا سكريبت — حلقة for...of تمرّ عليها حرفًا حرفًا:

index.js
Output
Click Run to see the output here.

يعمل هذا بشكل صحيح مع معظم نقاط Unicode أيضًا، وهي ميزة صغيرة لكنها حقيقية مقارنةً بالوصول إلى أحرف النص عبر رقم الفهرس.

الحصول على index في for of

الشيء الوحيد الذي لا تمنحك إياه حلقة for...of مباشرةً هو موضع العنصر. عندما تحتاجه، اجمع الحلقة مع entries():

index.js
Output
Click Run to see the output here.

تُرجع names.entries() أزواجًا على شكل [index, value]، ثم يقوم التفكيك (destructuring) بتقسيمها إلى متغيّرَين. هذا الأسلوب عادةً أنظف من العودة إلى حلقة for (let i = 0; ...) التقليدية لمجرّد أنك بحاجة إلى i.

for...in في جافا سكريبت: المرور على مفاتيح الكائن

حلقة for...in مُصمَّمة للكائنات العادية، وتمرّ على المفاتيح النصية القابلة للتعداد (enumerable):

index.js
Output
Click Run to see the output here.

لاحظ أنك تحصل على المفتاح فقط، لا على القيمة. وللوصول إلى القيمة، تعود إلى الكائن عبر user[key]. كل مفتاح هنا سلسلة نصية — حتى لو بدا وكأنه رقم.

كما أن for...in يصعد في سلسلة البروتوتايب (prototype chain)، مما يعني أنه قد يكشف عن خصائص موروثة. في الكائنات الحرفية (literal objects) التي تنشئها بنفسك، نادرًا ما يُشكّل ذلك مشكلة، لكن عند المرور على نُسخ (instances) من صنف (class) أو كائنات قادمة من مكتبة خارجية، يُفضَّل أن تتعامل بحذر:

index.js
Output
Click Run to see the output here.

Object.hasOwn(user, key) يتخطى أي شيء موروث. في الكود الحديث، معظم المطورين يتجنبون for...in تمامًا، ويستخدمون بدلاً منه Object.keys أو Object.values أو Object.entries — وهذا يقودنا مباشرة للقسم التالي.

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

بدلًا من for...in، استخدم for...of مع إحدى دوال Object.* المساعدة. اختر منها ما يناسب حالتك:

index.js
Output
Click Run to see the output here.

Object.entries مريحة جدًا بشكل خاص — تفكيك الزوج [key, value] يجعل الكود يُقرأ وكأنه جملة عادية. وبما أن هذه التوابع تُرجع فقط الخصائص القابلة للتعداد المملوكة للكائن نفسه، فلن تقلق من الخصائص الموروثة غير المرغوبة.

تجنّب استخدام for...in مع المصفوفات

تقنيًا، الأمر مسموح، لكنه يوقع المطورين في أخطاء متكررة:

index.js
Output
Click Run to see the output here.

ستحصل على 0 و1 و2، وأيضًا tag. أي خاصية أضافها أحدهم إلى المصفوفة — أو إلى Array.prototype عبر polyfill — ستظهر هي الأخرى. كما أن المفاتيح هنا عبارة عن نصوص (strings)، لذلك فإن key + 1 يقوم بدمج النصوص بدلًا من الجمع الحسابي. زِد على ذلك أن ترتيب المرور لا يضمن لك مطابقة ترتيب عناصر المصفوفة في كل الحالات.

قاعدة عامة تختصر لك الموضوع:

  • تريد قيم المصفوفة فقط؟ استخدم for...of arr.
  • تريد الـ index والقيمة معًا؟ استخدم for...of arr.entries().
  • تريد الـ index فقط مع عدّ يدوي؟ الحلقة الكلاسيكية for (let i = 0; i < arr.length; i++).
  • تريد المرور على مفاتيح أو خصائص كائن؟ استخدم Object.keys(obj) أو Object.entries(obj) مع for...of.

باختصار: for...in أداة لاستخدامات ضيقة جدًا، بينما for...of مع دوال Object المساعدة يغطّي لك كل ما تحتاجه عمليًا.

break وcontinue يعملان في الحلقتين

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

index.js
Output
Click Run to see the output here.

العبارة continue تتخطى الدورة الحالية وتنتقل للي بعدها، أما break فتخرج من الحلقة كلياً. وهذا بالضبط السبب الرئيسي اللي يخلّي for...of أفضل من .forEach() — لأن دالة الـ callback في forEach ما تقدر تستخدم break للخروج من الحلقة، بينما for...of تقدر.

مقارنة سريعة جنباً إلى جنب

index.js
Output
Click Run to see the output here.

أربع حلقات، أربع مهام، وفكرة واحدة تحكمها كلها: إذا كنت تريد القيم من شيء قابل للتكرار (iterable)، استخدم for...of. أما إذا أردت التعامل مع خصائص كائن، فمرّ عليها عبر Object.keys أو Object.values أو Object.entries، ومع for...of أيضًا. واترك for...in للحالة النادرة التي تحتاج فيها فعلًا إلى كل المفاتيح النصية القابلة للعدّ في كائن ما، سواء كانت موروثة أم لا.

التالي: القيم الصادقة والكاذبة (Truthy و Falsy)

كل حلقة وكل جملة if في جافا سكريبت تطرح في النهاية السؤال ذاته: هل تُعتبر هذه القيمة صحيحة؟ والإجابة ليست دائمًا بديهية — فالسلسلة الفارغة، والصفر، وnull، وundefined تتصرف كلها بشكل مختلف عمّا قد تتوقعه. القيم الصادقة والكاذبة هي موضوعنا القادم.

الأسئلة الشائعة

ما الفرق بين for...of و for...in في JavaScript؟

حلقة for...of تمر على قيم أي عنصر قابل للتكرار مثل المصفوفات والنصوص و Map و Set، بينما for...in تمر على مفاتيح (أسماء خصائص) الكائن. مثلاً في المصفوفة ['a', 'b']، تعطيك for...of القيمتين 'a' و 'b'، أما for...in فتعطيك '0' و '1' كسلاسل نصية.

هل يمكنني استخدام for...of مع الكائنات (Objects)؟

ليس بشكل مباشر، لأن الكائنات العادية ليست قابلة للتكرار. الحل هو استخدام Object.keys(obj) أو Object.values(obj) أو Object.entries(obj) للحصول على مصفوفة يمكنك المرور عليها بـ for...of. الصيغة الأكثر شيوعاً هي: for (const [key, value] of Object.entries(obj)).

لماذا يُنصح بعدم استخدام for...in مع المصفوفات؟

تقنياً تعمل، لكن for...in تمر على كل الخصائص القابلة للعدّ، بما فيها الخصائص الموروثة وأي إضافات على Array.prototype. كما أنها تُرجع المفاتيح كسلاسل نصية، والترتيب ليس مضموناً دائماً مع المفاتيح الرقمية. استخدم for...of إذا أردت القيم، أو حلقة for التقليدية إذا كنت بحاجة إلى الفهرس (index).

تعلّم البرمجة مع Coddy

ابدأ الآن