كيف تجتاز مقابلة JavaScript: أهم الأسئلة
مقابلة مطور JavaScript (خاصة مع التركيز على Node.js) ليست مجرد اختبار للصياغة النحوية. يرغب أصحاب العمل في رؤية فهم عميق لعدم التزامن (asynchrony)، ونطاقات الرؤية (scopes)، وآلية عمل Event Loop. في هذه المقالة، قمنا بتجميع أهم الأسئلة التي تُطرح فعلياً في المقابلات، مع أمثلة على الكود وشروحات.
1. الإغلاقات (Closures) — أساس البرمجة الوظيفية في JS
السؤال: "ما هو الإغلاق (closure) وكيف يعمل في Node.js؟"
الإغلاق هو دالة "تتذكر" بيئتها المعجمية (lexical environment) حتى بعد انتهاء تنفيذ الدالة الخارجية. هذه آلية أساسية لتغليف البيانات (encapsulation) في JavaScript.
function createCounter() { let count = 0; return function() { count++; return count; };}
const counter = createCounter();console.log(counter()); // 1console.log(counter()); // 2لماذا يُطرح هذا السؤال: الإغلاقات هي أساس الوحدات (modules)، ومصانع الدوال (function factories)، ومعالجات الأحداث (event handlers) في Node.js. بدون فهم الإغلاقات، لا يمكن العمل مع الاستدعاءات غير المتزامنة (asynchronous callbacks).
2. Event Loop وعدم التزامن (Async/Await, Promises)
السؤال: "اشرح كيف يعمل Event Loop. ماذا سيطبع هذا الكود؟"
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');الإجابة: 1, 4, 3, 2. أولاً الكود المتزامن (synchronous)، ثم المهام الصغيرة (microtasks - Promise.then)، ثم المهام الكبيرة (macrotasks - setTimeout).
Event Loop هي آلية تسمح لـ Node.js بتنفيذ عمليات غير محظورة (non-blocking) على الرغم من كونه أحادي الخيط (single-threaded). يتكون من عدة مراحل:
- المؤقتات (Timers) — تنفيذ استدعاءات setTimeout/setInterval
- استدعاءات الإدخال/الإخراج (I/O callbacks) — معالجة عمليات الإدخال/الإخراج المكتملة
- الاستقصاء (Poll) — الحصول على أحداث I/O جديدة
- الفحص (Check) — تنفيذ setImmediate()
- استدعاءات الإغلاق (Close callbacks) — إغلاق الاتصالات
نصيحة: في المقابلة، أظهر فهمك للفرق بين process.nextTick() و setImmediate(). يتم تنفيذ nextTick قبل المرحلة التالية من Event Loop، بينما يتم تنفيذ setImmediate في مرحلة Check.
3. سياق الاستدعاء (this) والدوال السهمية (Arrow Functions)
السؤال: "ماذا تساوي this في حالات مختلفة؟ كيف يمكن تغيير السياق؟"
قيمة this تُحدد بناءً على كيفية استدعاء الدالة، وليس أين تم تعريفها. في Node.js (الوضع الصارم - strict mode)، في الدالة العادية ستكون this مساوية undefined، بينما في المتصفح ستكون window.
const obj = { name: 'Node.js', regularFunc: function() { console.log(this.name); }, arrowFunc: () => { console.log(this.name); }};
obj.regularFunc(); // 'Node.js'obj.arrowFunc(); // undefined (this مأخوذة من السياق الخارجي)كيفية التحكم في السياق:
call(thisArg, arg1, arg2)— تستدعي الدالة مع this والوسائط المحددةapply(thisArg, [args])— مشابه، لكن الوسائط تُمرر كمصفوفةbind(thisArg)— تنشئ دالة جديدة مع this مربوط- الدوال السهمية (Arrow Functions) — ليس لها this خاص بها، بل تستخدم السياق المعجمي (lexical context)
4. النماذج الأولية (Prototypes) والوراثة (Prototype Chain)
السؤال: "كيف تعمل الوراثة النموذجية (prototypal inheritance) في JavaScript؟ ما الفرق بينها وبين الكلاسات (classes)؟"
JavaScript تستخدم الوراثة النموذجية: كل كائن لديه مرجع داخلي [[Prototype]] (يمكن الوصول إليه عبر __proto__ أو Object.getPrototypeOf()).
function Animal(name) { this.name = name;}
Animal