Menu
العربية

Destructuring في JavaScript: شرح شامل بالأمثلة

تعلّم كيف يعمل الـ destructuring في JavaScript لاستخراج القيم من الكائنات والمصفوفات، مع إعادة التسمية، القيم الافتراضية، الأنماط المتداخلة، وباراميترات الدوال.

التفكيك في JavaScript: مطابقة أنماط على شكل البيانات

يتيح لك destructuring في javascript كتابة نمط يحاكي شكل الكائن أو المصفوفة، ثم تسحب القيم بالاسم أو بالموقع في سطر واحد. فبدلاً من الوصول إلى الخاصية تلو الأخرى يدويًا، أنت تصف ما تريده وتترك لـ JavaScript مهمة تسليمه لك.

هناك نوعان أساسيان:

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

الأقواس المعقوفة {} تُطابِق الكائن حسب اسم الخاصية، بينما الأقواس المربعة [] تُطابِق المصفوفة حسب الموضع. وفي كلتا الحالتين، المتغيرات التي تكتبها قبل علامة المساواة هي تصريحات جديدة — أنت لا تصل إلى قيمة داخل الكائن، بل ترسم نمطًا يصف كيف تُستخرَج الأجزاء منه.

قبل ظهور الـ destructuring في javascript، كانت نفس الشيفرة تُكتب هكذا:

const name = user.name;
const age = user.age;
const first = scores[0];
const second = scores[1];

ليست كارثة، لكنها تصبح مُملّة حين تكرّرها في كل دالة.

تفكيك الكائنات يعتمد على أسماء الخصائص

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

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

إذا لم تكن الخاصية موجودة على الكائن، ستكون قيمة المتغير undefined دون أن يحدث أي خطأ:

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

سلوك undefined الصامت هذا من الأشياء المهمة اللي لازم تحطها في بالك، خصوصًا لما تلاقي نفسك الساعة ٢ بعد نص الليل تبحث عن سبب مشكلة اتضح إنها مجرد خطأ إملائي في اسم الخاصية.

إعادة تسمية المتغير في destructuring

أحيانًا اسم الخاصية الموجود في الكائن مش الاسم اللي تحب تستخدمه كمتغير — يمكن يتعارض مع اسم تاني في نفس النطاق، أو إن الـ API يستخدم تسمية ما تعجبك. في هذه الحالة تقدر تستخدم الصيغة original: newName لإعادة الربط باسم جديد:

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

اقرأها هكذا: "خذ الخاصية id، وسمِّها userId". اسم الخاصية يأتي أولاً، ثم اسم المتغير الجديد بعد النقطتين. قد يبدو هذا للوهلة الأولى شبيهاً بتحديد نوع المتغير كما في لغات أخرى، لكنه ليس كذلك.

القيم الافتراضية في destructuring

إذا كانت هناك خاصية قد لا تكون موجودة، فاضبط لها قيمة افتراضية داخل نمط التفكيك مباشرةً:

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

القيم الافتراضية لا تُستخدم إلا عندما تكون القيمة undefined فقط. أما null و 0 و "" فتمر كما هي دون أي تغيير:

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

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

يمكنك أيضاً الجمع بين القيم الافتراضية وإعادة تسمية المتغير في آنٍ واحد:

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

تفكيك المصفوفات في JavaScript يعتمد على الترتيب

المصفوفات ما فيها أسماء مفاتيح، بس مؤشرات (indices)، عشان كذا عملية تفكيك المصفوفات في JavaScript تتم حسب الترتيب. وإذا بغيت تتجاوز عنصر ما يهمّك، استخدم الفواصل بدون اسم متغير:

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

الفاصلتان في البداية تعنيان "تجاوز العنصر رقم 0 والعنصر رقم 1". الشكل قد يبدو مزدحمًا بصريًا، لكنه مفيد عندما تريد قيمة واحدة فقط من منتصف المصفوفة.

يتألق تفكيك المصفوفات في javascript مع الدوال التي تُرجع عدة قيم على شكل tuple:

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

نفس النمط بتلاقيه في كل مكان داخل React hooks: const [count, setCount] = useState(0).

نمط rest: تجميع ما تبقى من القيم

داخل أي نمط destructuring، الصيغة ...name بتجمّع كل القيم اللي ما اتطابقتش بالاسم أو بالترتيب وتحطها في متغير جديد.

مع المصفوفات، rest بياخد باقي العناصر:

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

بالنسبة للكائنات، يلتقط rest كل خاصية لم يتم ذكرها بشكل صريح:

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

هذه هي الطريقة المتعارف عليها لإزالة حقل واحد من كائن دون تعديله — حيث يصبح rest كائنًا جديدًا يحتوي على كل شيء ما عدا id.

يجب أن يأتي rest في آخر النمط دائمًا. كتابة const [...init, last] تُعدّ خطأً نحويًا.

التفكيك المتداخل (Nested Destructuring)

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

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

قويّة فعلاً، لكن استخدمها بحذر. بمجرد ما تصل لثلاث مستويات من الأقواس المتداخلة، تبدأ تحسّها لغزاً. لمّا يحصل هذا، استخرج القيم الوسيطة في متغيرات مستقلة — الوضوح أهم من الاستعراض.

تنبيه مهم: data: { user } داخل النمط لا يُنشئ متغيراً اسمه data. هذه مجرد تعليمة تقول: "ادخل إلى data وواصل التفكيك." لو كنت تحتاج data نفسه، أضفه بشكل منفصل:

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

تفكيك باراميترات الدوال

أكثر مكان ستستخدم فيه destructuring في javascript هو قائمة باراميترات الدالة. فبدلاً من تمرير "كائن إعدادات" غامض، يتحوّل توقيع الدالة إلى شيء يوثّق نفسه بنفسه:

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

في موقع الاستدعاء، يبدو الأمر كأي استدعاء عادي يمرّر كائن خيارات. أما داخل الدالة، فتحصل على متغيرات مسمّاة بقيم افتراضية جاهزة — وداعًا لتكرار النمط الممل options.name || "default".

لكن انتبه لمزلق دقيق هنا: استدعاء الدالة بدون أي وسيط سيتسبب في خطأ، لأنك ببساطة لا تستطيع تفكيك undefined. الحل أن تضع قيمة افتراضية للباراميتر نفسه ككل:

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

العبارة = {} بعد النمط تقول: "إذا لم يُمرَّر أي وسيط، اعتبر أنه كائن فارغ." بعدها تتكفّل القيم الافتراضية الداخلية بالباقي.

التبديل وإعادة الإسناد

يعمل destructuring مع المتغيرات المُعلَنة مسبقًا أيضًا، لكن عليك إحاطة نمط الكائن بأقواس هلالية، وإلا فسيقرأ JavaScript الرمز { على أنه بداية كتلة برمجية:

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

تبديل عناصر المصفوفة بهذه الطريقة أنيق جدًا. أما إعادة إسناد الكائنات فنادرًا ما تحتاجها، لكن حيلة الأقواس تستحق أن تحفظها في ذهنك لوقت الحاجة.

مثال واقعي

لنجمع الآن معظم ما سبق في دالة تتعامل مع استجابة قادمة من واجهة API:

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

كل طبقة من طبقات التفكيك لها قيمة افتراضية، ممّا يجعل الدالة تتعامل مع البيانات الناقصة دون الحاجة إلى كومة من شروط if. هذه هي الفائدة الحقيقية: توقيعات دوال دقيقة ومتسامحة في الوقت نفسه.

ما التالي؟ عامل النشر على الكائنات (Object Spread)

التفكيك (destructuring) يُخرج القيم من الكائنات، بينما عامل النشر (spread) يُدخلها — فيُستخدم للنسخ والدمج والاستبدال. الاثنان رفيقان دائمان في JavaScript الحديثة، والمحطة التالية هي عامل النشر.

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

ما هو الـ destructuring في JavaScript؟

الـ destructuring هو صياغة تسمح لك باستخراج القيم من الكائنات أو المصفوفات وربطها بمتغيرات في خطوة واحدة. مثلاً const { name } = user; تأخذ الخاصية name من الكائن user، وconst [first, second] = list; تأخذ أول عنصرين من list. باختصار: نمط تكتبه على يسار علامة = يعكس شكل القيمة الموجودة على اليمين.

كيف يمكن إعادة تسمية المتغير أثناء الـ destructuring؟

استخدم الصياغة { original: newName }. فمثلاً const { name: username } = user; تأخذ الخاصية name من user وتربطها بمتغير محلي اسمه username. انتبه: كثيرين يخلطون بينها وبين تعريف النوع — تذكّر أن اسم الخاصية يأتي أولاً، ثم اسم المتغير الجديد بعد النقطتين :.

هل يمكن تعيين قيم افتراضية مع الـ destructuring؟

نعم. مثل const { timeout = 5000 } = options; تستخدم 5000 فقط إذا كانت options.timeout تساوي undefined. لاحظ أن القيم الافتراضية تُطبَّق على undefined فقط — أمّا null و0 و'' فتمرّ كما هي. ويمكن دمج القيمة الافتراضية مع إعادة التسمية هكذا: const { t: timeout = 5000 } = options;.

ما الفرق بين الـ destructuring والـ spread؟

يتشابهان في الشكل لكن وظيفتهما معاكسة. الـ destructuring مثل const { a, b } = obj يُخرج القيم من بنية معيّنة، بينما الـ spread مثل const copy = { ...obj } يضع القيم داخل بنية جديدة. أمّا ... داخل نمط الـ destructuring فهو rest pattern، أي يجمع باقي القيم غير المستخرجة في متغير واحد.

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

ابدأ الآن