المرحلة 0 · الأسبوع 2 · الدرس 0005 · ~45 دقيقة

قواعد الـ this الأربعة — بص على النداء، مش على التعريف

ليه الدرس ده؟ الـ this هي المنطقة اللي بيغرق فيها معظم مطوري JS — وأسئلتها شبه مضمونة في الانترفيوهات. والأهم: هي عكس الـ scope تماماً، والمقارنة دي هي اللي هتثبت الاتنين في دماغك.

🔁 مراجعة سريعة قبل ما تبدأ (~5 دقايق):

١ — الفكرة في 3 جمل

① الـ this = "الأوبجكت اللي الدالة شغالة لصالحه في النداء ده" — وفاكر من درس 0001 إن كل execution context بيتحدد فيه this وقت إنشائه؟ أهو ده هو.

② المفاجأة الكبرى: الـ this بيتحدد من شكل سطر النداء لحظة التنفيذ — مش من مكان كتابة الدالة. يعني نفس الدالة الواحدة ممكن يبقى ليها this مختلف في كل نداء!

③ فيه بالظبط 4 قواعد بتحدده، وليهم ترتيب أولوية — بتسأل الأسئلة بالترتيب وأول قاعدة تنطبق بتكسب.

⚖️ المقارنة الذهبية (دي اللي بتتحفظ): في درس 0004 حفظنا إن الـ scope بيتحدد بمكان الكتابة (lexical). النهاردة بنضيف نصها التاني: الـ this بيتحدد بطريقة النداء (dynamic). متغيراتك بتتحل بالكتابة، والـ this بيتحل بالنداء — خطين متوازيين ماتخلطهمش.

⚠️ حدود الدرس: الـ arrow functions ليها حكاية مختلفة تماماً مع this — دي درس لوحدها بعد ده إن شاء الله. كل اللي هنا عن الدوال العادية.

٢ — القواعد الأربعة (بترتيب الأولوية)

الأولويةالقاعدةشكل النداءthis بيبقى
1new bindingnew Person()الأوبجكت الجديد اللي بيتبني
2explicit bindingf.call(obj) / f.apply(obj) / f.bind(obj)الـ obj اللي انت حددته بإيدك
3implicit bindingobj.f() — فيه نقطة (الرمز . اللي بين الأوبجكت واسم الدالة)الأوبجكت اللي قبل النقطة
4default bindingf() — نداء ساكت من غير أي حاجةglobalThis (أو undefined في strict mode)

طريقة الاستخدام: بص على سطر النداء واسأل بالترتيب: فيه new؟ فيه call/apply/bind؟ فيه نقطة؟ ولا ولا حاجة؟ — أول "أيوه" بتقفل الموضوع.

📌 يعني إيه "strict mode" اللي في قاعدة 4؟ وضع تشغيل أكثر صرامة للغة (بيتفعل بـ "use strict" أو تلقائياً جوه ES Modules والـ classes) بيحول الأخطاء الصامتة لصريحة — نفس فلسفة الـ TDZ. أثره هنا: النداء الساكت يخلي this = undefined بدل globalThis، فلمسة this.name بترمي TypeError بدل الكتابة على الـ global في صمت. مهم عملياً: كودك في Vue/Nuxt كله ES Modules = strict تلقائياً. القصة الكاملة في الأسبوع 8 إن شاء الله.

✓ القواعد الأربعة وترتيب أولويتهم متحقق منهم بتشغيل Node.js فعلي (2026-08-04).

٣ — شوفها بعينك: الـ this جوه كل context

نفس محاكي الـ Call Stack بتاع 0001 — بس النجم المرة دي هو سطر الـ this جوه كل frame (أخضر = مظبوط زي ما تتوقع، أحمر = الفخ). نفس الدالة hi هتتندى 3 مرات بتلات نتايج مختلفة — توقع قبل كل خطوة!

const user = {
  name: "عمر",
  hi() { console.log("أهلاً " + this.name); }
};
user.hi();
const f = user.hi;
f();
f.call(user);
دوس «خطوة» عشان نبدأ.
Console:
Call Stack + الـ this جوه كل context

٤ — الفخ الأشهر في JS كلها: النقطة الضايعة

const f = user.hi;
f();   // "أهلاً undefined"

اللي حصل في السطرين دول: خدنا الدالة نفسها (والنقطة مش بتتخزن معاها)، وبعدين نديناها نداء ساكت ← فقاعدة default اشتغلت ← فـ this.name طلعت undefined.

لما بتعمل const f = user.hi أنت بتنسخ مؤشر للدالة بس — علاقتها بـ user مش جزء منها. الـ implicit binding بيتحسب من شكل النداء نفسه كل مرة: user.hi() فيها الرمز . فقاعدة 3 بتكسب، أما f() فمن غير نقطة فبتقع للـ default.

🔑 التفرقة اللي بتفك كل اللخبطة: نقطة القراءة ≠ نقطة النداء. user.hi من غير أقواس = قراءة (بتجيب الدالة بس — مالهاش علاقة بالـ this). أما obj2.hi() بالأقواس = نداء، ودي بس اللي بتحدد this. الدالة نفسها مالهاش صاحب ولا ذاكرة — اسأل دايماً: "النقطة اللي جنب أقواس التشغيل ()، قبلها مين؟"

ونفس الفخ ده بيحصل مع الـ callback (يعني: دالة بتديها لكود تاني عشان يناديها هو بعدين — زي addEventListener وsetTimeout):

setTimeout(user.hi, 1000);   // "أهلاً undefined"

اللي بيحصل هنا: أنت بتبعت مؤشر الدالة بس لـ setTimeout (زي const f = user.hi بالظبط)، وبعد ثانية setTimeout بينده النداء من عنده ساكت من غير نقطة ← فبتقع لقاعدة default ← فبتطبع "أهلاً undefined".

هتقابل الفخ ده بشكل يومي في شغلك الحقيقي مع الـ events والـ timers. ✓ متحقق منه بتشغيل Node فعلي (2026-08-05) — والحلول (bind والـ arrow functions) هما بالظبط الدرسين الجايين إن شاء الله.

٥ — توقع قبل ما تشوف (3 تمارين)

const user = { name: "عمر", hi() { console.log("أهلاً " + this.name); } };
const greet = user.hi;
greet();
user.hi.call({ name: "سارة" });
const obj2 = { name: "نور", hi: user.hi };
obj2.hi();

٦ — اختبر نفسك

س1: user.hi.call(other) — فيه نقطة وفيه call مع بعض. مين this؟

س2: إيه اللي بيحدد قيمة this لدالة عادية؟

س3: ليه const f = user.hi; f(); بتفقد الـ this؟

س4 (سؤال judgment): الـ scope بالكتابة والـ this بالنداء — إيه النتيجة العملية للفرق ده؟

٧ — التحدي الأخير: اشرحها بصوت عالي

من غير ما تبص على أي حاجة — امشي على السطور دي سطر سطر، وقول عند كل نداء: أنهي قاعدة انطبقت، وليه، وإيه اللي اتطبع — واقفل بحالة البرنامج النهائية:

const cat = { name: "بسبس", speak() { console.log(this.name + " بيقول ميو"); } };
cat.speak();
const talk = cat.speak;
talk();
talk.call({ name: "قطقوطة" });

٨ — المصدر الأساسي للتعمق