call و apply في جافا سكريبت: أهم الأخطاء وكيفية تجنبها
هل سبق لك أن نظرت إلى كود جافا سكريبت لشخص آخر ورأيت تركيبات غريبة مثل func.call(this, arg1, arg2) أو func.apply(this, [arg1, arg2])؟ وتساءلت: "ما الفرق في الأساس؟" إذا كان الأمر كذلك، فأنت لست وحدك. سؤال "ما الفرق بين call و apply؟" هو أحد أكثر الأسئلة شيوعًا على Stack Overflow بمئات الآلاف من المشاهدات. وهذا ليس من قبيل الصدفة.
الخلط بين call و apply هو فخ كلاسيكي للمبتدئين (وليس فقط). في هذه المقالة، لن نكتفي بشرح النظرية. سنحلل أهم 5 أخطاء حقيقية، ونوضح كيفية إصلاحها، ونقدم خوارزمية واضحة ستخلصك من الحيرة إلى الأبد. هيا بنا!
نبذة مختصرة: ما هما call و apply؟
قبل الغوص في الأخطاء، دعنا ننعش الأساسيات. الطريقتان call و apply هما طريقتان مدمجتان في الدوال في جافا سكريبت. مهمتهما الرئيسية هي تحديد سياق الاستدعاء (this) بشكل صريح للدالة. بمعنى آخر، تسمحان لك بقول: "أيها الدالة، تخيلي أنك تعملين مع هذا الكائن".
الصيغة:
func.call(context, arg1, arg2, ...);func.apply(context, [arg1, arg2, ...]);الفرق الرئيسي:
callتقبل الوسائط مفصولة بفاصلة (قائمة).applyتقبل الوسائط على شكل مصفوفة (أو كائن شبيه بالمصفوفة).
هذا كل شيء. هذا هو الاختلاف الوحيد. ولكن بسبب هذا "الأمر التافه" تنشأ معظم الأخطاء. دعنا نحللها.
أهم 5 أخطاء عند العمل مع call و apply
الخطأ رقم 1: الخلط في قائمة الوسائط (الأكثر شيوعًا!)
هذا هو "ملك" جميع الأخطاء. لقد كتبت دالة تتوقع وسائط واحدة تلو الأخرى، ولكنك مررت مصفوفة عبر call. أو العكس.
مثال كارثي:
function greet(greeting, punctuation) { console.log(greeting + ', ' + this.name + punctuation);}
const user = { name: 'آنا' };
// خطأ: نمرر مصفوفة، لكننا نستخدم callgreet.call(user, ['مرحبًا', '!']); // الإخراج: "مرحبًا,! آنا,undefined" — هراء تام!لماذا يحدث هذا؟ call تتوقع وسائط واحدة تلو الأخرى. لقد تلقت وسيطًا واحدًا - مصفوفة كاملة - ووضعتها في المتغير greeting. بقي punctuation غير معرف (undefined).
كيف تصلحه؟ استخدم apply إذا كانت البيانات موجودة بالفعل في مصفوفة:
greet.apply(user, ['مرحبًا', '!']); // الإخراج: "مرحبًا, آنا!" — صحيح!أو قم بفرد المصفوفة باستخدام عامل الانتشار (المنهج الحديث):
greet.call(user, ...['مرحبًا', '!']); // يعمل أيضًا!الخطأ رقم 2: نسيان أن apply تعمل مع الكائنات الشبيهة بالمصفوفة
يعتقد الكثيرون أن apply تقبل فقط مصفوفة حقيقية. في الواقع، هي تقبل أي كائن شبيه بالمصفوفة: يجب أن يحتوي على خاصية length ومفاتيح رقمية.
مثال:
function sum() { let total = 0; for (let i = 0; i < arguments.length; i++) { total += arguments[i]; } return total;}
// نمرر ليس مصفوفة، بل كائنًا مع lengthconst args = { 0: 5, 1: 10, 2: 15, length: 3 };
console.log(sum.apply(null, args)); // الإخراج: 30 — يعمل!لكن كن حذرًا: إذا لم يكن للكائن خاصية length، فإن apply ستتجاهله ببساطة. هذا خطأ شائع عند العمل مع arguments (كائن قديم) أو مع NodeList.
الخطأ رقم 3: استخدام call/apply حيث يكفي استدعاء بسيط
أحيانًا يسيء المبتدئون استخدام