مقدمة: لماذا يعتبر دمج الكائنات كابوسًا لكل مطور JavaScript
تخيل: أنت تعمل على تطبيق، وتحتاج إلى دمج بيانات من مصدرين مختلفين. على سبيل المثال، لديك إعدادات أساسية للمستخدم من قاعدة البيانات وإعدادات قادمة من الواجهة الأمامية. كيف تدمجها دون ألم ومعاناة؟ هذا السؤال بالتحديد — «How can I merge properties of two JavaScript objects?» — حصد آلاف المشاهدات على Stack Overflow. وليس من دون سبب: دمج الكائنات في JavaScript يخفي العديد من المزالق.
في هذه المقالة، سنستعرض جميع الطرق الشائعة لدمج الكائنات في JS: من الطريقة الكلاسيكية Object.assign() إلى عامل الانتشار الحديث (spread operator). ستتعلم كيفية النسخ العميق للهياكل المتداخلة، وتجنب تغيير البيانات الأصلية، واختيار الطريقة المناسبة لمهمتك. هيا بنا!
المشكلة: ماذا يعني «دمج خصائص كائنين»؟
عندما نقول «merge objects JavaScript»، فإننا نعني إنشاء كائن جديد يحتوي على جميع الخصائص من الكائنات الأصلية. إذا تكررت المفاتيح، فإن القيمة من الكائن الثاني «تستبدل» القيمة من الكائن الأول.
لنفترض أن لدينا كائنين:
const user = { name: 'آنا', age: 28, city: 'موسكو'};
const updates = { age: 29, job: 'مطور'};بعد دمج الكائنات في JS نريد الحصول على:
{ name: 'آنا', age: 29, // قيمة محدثة city: 'موسكو', job: 'مطور' // خاصية جديدة}يبدو الأمر بسيطًا. لكن الشيطان يكمن في التفاصيل: الكائنات المتداخلة، المصفوفات، تغيير الأصل والأداء.
الطريقة 1: Object.assign() — الكلاسيكي القديم الجيد
طريقة Object.assign() هي أقدم وأثبت طريقة لدمج الكائنات في JavaScript. تقوم بنسخ الخصائص المعدودة الخاصة من كائن مصدر واحد أو أكثر إلى الكائن الهدف.
الصيغة
Object.assign(target, ...sources)هام: الوسيط الأول هو الكائن الهدف الذي سيتم تعديله. جميع الوسائط التالية هي مصادر الخصائص.
مثال على الدمج
const user = { name: 'آنا', age: 28 };const updates = { age: 29, job: 'مطور' };
const merged = Object.assign({}, user, updates);console.log(merged);// { name: 'آنا', age: 29, job: 'مطور' }لاحظ: نمرر كائنًا فارغًا {} كهدف. هذا يضمن عدم تغيير الكائنات الأصلية — استنساخ الكائنات في JS يتم بشكل صحيح.
المزلق: النسخ السطحي
Object.assign() يقوم فقط بالنسخ السطحي (shallow copy). إذا كان لديك كائنات متداخلة، فسيتم نسخها بالإشارة:
const obj1 = { data: { value: 10 } };const obj2 = { info: 'test' };
const merged = Object.assign({}, obj1, obj2);merged.data.value = 999;console.log(obj1.data.value); // 999 — تغيير الكائن الأصلي!للدمج العميق، ستحتاج إلى طرق أخرى سنتحدث عنها أدناه.
الطريقة 2: عامل الانتشار (Spread Operator) — أناقة ES6
مع ظهور ES6، أصبح عامل الانتشار في JavaScript (النقاط الثلاث ...) الطريقة الأكثر شيوعًا لدمج خصائص الكائنات. إنه موجز، قابل للقراءة، ولا يتطلب استدعاء دالة.
الصيغة
const merged = { ...obj1, ...obj2 };مثال
const defaults = { theme: 'light', lang: 'ar', showSidebar: true };const userPrefs = { theme: 'dark', fontSize: 16 };
const settings = { ...defaults, ...userPrefs };console.log(settings);// { theme: 'dark', lang: 'ar', showSidebar: true, font