تفكيك أعمق مما رأيت سابقًا
في درس الكائنات تعرّفت على تفكيك أساسي: let { name, age } = person. لكن التفكيك (Destructuring) أداة أقوى بكثير من ذلك — تعمل مع المصفوفات أيضًا، تدعم التداخل، ولها استخدامات يومية توفّر عليك أسطرًا كثيرة. هذا الدرس يغطّيها كاملة.
تفكيك المصفوفات (Array Destructuring)
بعكس الكائنات، التفكيك هنا بالترتيب لا بالاسم:
let colors = ["أحمر", "أخضر", "أزرق"];
let [first, second, third] = colors;
console.log(first, second, third); // أحمر أخضر أزرق
تخطّي عناصر
let [first, , third] = colors; // نتجاهل الثاني بفاصلة فارغة
console.log(first, third); // أحمر أزرق
قيم افتراضية
تُستخدم فقط إذا كانت القيمة undefined تحديدًا:
let [a = 10, b = 20] = [5];
console.log(a, b); // 5 20 (b لا يوجد بالمصفوفة فأخذ الافتراضي)
let [c = 10] = [undefined];
console.log(c); // 10
let [d = 10] = [null];
console.log(d); // null — القيمة الافتراضية لا تُستخدم مع null، فقط undefined
تبديل قيمتين دون متغيّر مؤقّت 🌟
من أشهر استخدامات تفكيك المصفوفات:
let x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); // 2 1
💡 قبل هذا الأسلوب، كان تبديل قيمتين يحتاج متغيّرًا ثالثًا مؤقتًا. سطر واحد يكفي الآن.
التفكيك المتداخل (Nested Destructuring)
يعمل مع كائنات ومصفوفات متداخلة داخل بعضها بأي عمق:
let user = {
name: "سارة",
address: { city: "عمّان", country: "الأردن" },
hobbies: ["قراءة", "سباحة"],
};
let {
name,
address: { city },
hobbies: [firstHobby],
} = user;
console.log(name, city, firstHobby); // سارة عمّان قراءة
🔑 لاحظ أن
addressوhobbiesأنفسهما لم يصبحا متغيّرين — فقط ما بداخل أقواسهما استُخرج. إن أردتaddressنفسه أيضًا، أضفه صراحة:{ address, address: { city } }.
إعادة التسمية أثناء التفكيك
مفيدة عند تعارض الاسم مع متغيّر موجود، أو لاسم أوضح محليًا:
let product = { id: 101, price: 25 };
let { id: productId, price: cost } = product;
console.log(productId, cost); // 101 25
// product.id لا يزال موجودًا؛ فقط اسم المتغيّر المحلي تغيّر
المتبقي (Rest) في التفكيك
يجمع كل ما تبقّى — مختلف عن الانتشار (Spread) الذي تعلّمته سابقًا: الانتشار يوزّع عناصر لكائن أو مصفوفة جديدة، بينما المتبقي يجمع ما لم يُفكَّك صراحة في متغيّر واحد.
// مصفوفة
let [winner, ...others] = ["عمر", "سارة", "خالد", "ليلى"];
console.log(winner); // عمر
console.log(others); // ["سارة", "خالد", "ليلى"]
// كائن
let { id, ...restOfProduct } = { id: 1, name: "قلم", price: 3 };
console.log(id); // 1
console.log(restOfProduct); // { name: "قلم", price: 3 }
🔑 عنصر
...restيجب أن يكون الأخير بنمط التفكيك دائمًا — لا يوجد معنى لعناصر بعده.
تفكيك معاملات الدوال 🌟
الاستخدام الأكثر فائدة عمليًا: بدل تمرير عدة معاملات بترتيب محدد يصعب تذكّره، مرّر كائنًا واحدًا وفكّكه في تعريف الدالة — يشبه "المعاملات المسمّاة" بلغات أخرى:
function createUser({ name, age = 18, role = "member" } = {}) {
return `${name}, ${age}, ${role}`;
}
createUser({ name: "ليلى" }); // ليلى, 18, member
createUser({ name: "خالد", role: "admin" }); // خالد, 18, admin
createUser(); // بلا خطأ بفضل = {} بالنهاية
- الترتيب لم يعد مهمًا عند الاستدعاء.
- كل معامل يقدر يأخذ قيمة افتراضية مستقلة.
= {}في نهاية نمط التفكيك يجعل تمرير الكائن كله اختياريًا؛ بدونها، استدعاء الدالة بلا معاملات يرمي خطأ لأنه يحاول تفكيكundefined.
أخطاء شائعة
- ❌ تفكيك
nullأوundefinedمباشرة →let { x } = null;يرميTypeErrorفورًا، لأن لا يوجد شيء لتفكيكه. - ❌ الظن أن القيمة الافتراضية تعمل مع
null→ تعمل فقط معundefined، وnullقيمة صريحة تبقى كما هي. - ❌ نسيان
= {}بمعامل دالة مفكَّك اختياري → استدعاء الدالة بلا أي معامل يرمي خطأ بدلًا من استخدام الافتراضيات. - ❌ وضع
...restبمنتصف نمط التفكيك → خطأ صياغة؛ يجب أن يكون العنصر الأخير دائمًا.
خلاصة
تفكيك المصفوفات بالترتيب، وتفكيك الكائنات بالاسم، وكلاهما يدعمان التداخل والقيم الافتراضية والمتبقي ...rest. أقوى استخدام عملي: تفكيك معاملات الدوال لكتابة دوال أوضح بمعاملات مسمّاة واختيارية.
🎯 التالي: عوامل الإسناد المنطقي والسلسلة الاختيارية المتقدمة.