أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول
البرمجة بالعربي

ليه this بيتغيّر معناه في JavaScript: 4 قواعد تحسمها

📅 ٢٢ مايو ٢٠٢٦⏱ 7 دقائق قراءة
ليه this بيتغيّر معناه في JavaScript: 4 قواعد تحسمها

مستوى المقال: متوسط. الكلام ده موجّه لحد كتب JavaScript قبل كده، وعارف يعمل function و object، لكن كلمة this لسه بتفاجئه بنتايج غريبة. لو لسه بتبدأ من الصفر، اقرأه على مهلك؛ فيه مثال من الحياة قبل كل جزء تقني.

ليه this بيتغيّر معناه في JavaScript

لو زرار شغّال تمام عندك دلوقتي بيرمي Cannot read properties of undefined بمجرد ما تنقله جوّه setTimeout أو تبعته كـ callback، المشكلة مش في الكود اللي جوّه الدالة. كلمة this بصّت لمكان تاني. المقال ده بيديك أربع قواعد تحسم قيمة this في أي سطر من غير تخمين، وبيوضّح ليه الدالة السهمية بتحل أغلب الوجع ده.

رسم توضيحي للكلمة this في JavaScript داخل دائرة صفراء تتفرّع منها أربع نقاط اتصال تمثّل القواعد الأربعة لتحديد قيمتها

المشكلة باختصار

أغلب المطورين بيفتكروا إن this بتشير لـ«الكائن اللي الدالة متعرّفة جوّاه». الفكرة دي غلط، وبتفشل بالظبط في اللحظة اللي بتنقل فيها الدالة من مكانها: تبعتها لـ addEventListener، تخزّنها في متغير، تمرّرها لـ map. this في JavaScript مش مربوطة بمكان كتابة الدالة. هي مربوطة بطريقة استدعائها. الفرق ده بالظبط هو سبب أغلب الـ bugs اللي ليها علاقة بـ this.

مثال من الحياة قبل الكود

قبل أي كود، خد المثال ده. كلمة «أنا» في اللغة العربية مالهاش صاحب ثابت. لمّا تقول انت «أنا جعان»، الكلمة بتشير ليك. لمّا صاحبك يقول نفس الجملة، نفس الكلمة بتشير له هو. الكلمة اتنطقت بنفس الحروف، لكن اللي بتشير له بيتحدّد ساعة النطق، مش وقت ما الكلمة اتكتبت في القاموس.

this هي بالظبط كلمة «أنا» بتاعة الدوال. لمّا تكتب this جوّه دالة، انت مش بتحدّد قيمتها. القيمة بتتحدّد كل مرة الدالة بتتنادى فيها، وبتعتمد على إزاي نادتها. نفس الدالة ممكن ترجّع this مختلفة في كل استدعاء. ده مش عيب في اللغة؛ ده تصميم مقصود اسمه الربط الديناميكي (dynamic binding).

التعريف الدقيق

بعد المثال، التعريف العلمي. كل استدعاء لأي دالة في JavaScript بيعمل سياق تنفيذ (execution context). من ضمن مكوّنات السياق ده حاجة اسمها this binding. القيمة دي بتتحطّ لحظة الاستدعاء حسب صيغة النداء، وبتفضل ثابتة طول ما الدالة شغّالة. يعني this مش متغيّر عادي ومش بتورّث من الـ scope زي باقي المتغيرات؛ هي قيمة بتُحقَن من جديد في كل استدعاء.

القواعد الأربعة بالترتيب

عشان تعرف قيمة this في أي سطر، بُصّ على صيغة الاستدعاء وطبّق القواعد دي. أول قاعدة تتحقّق هي اللي بتحسم القيمة.

  1. الاستدعاء الحر: fn() من غير أي حاجة قبلها. هنا this بتساوي undefined في الوضع الصارم strict mode، أو الكائن العام (window في المتصفح) من غيره.
  2. الاستدعاء كميثود: obj.fn(). this بتساوي الكائن اللي على يسار النقطة، يعني obj.
  3. الاستدعاء الصريح: fn.call(x) أو fn.apply(x) أو نسخة معمولة بـ fn.bind(x). this بتساوي x اللي انت مرّرته بإيدك.
  4. الاستدعاء بـ new: new Fn(). بيتعمل كائن جديد فاضي وthis بتشير له.
JavaScript
"use strict";

function whoAmI() {
  return this;
}

// 1) استدعاء حر
whoAmI();                       // undefined  (في strict mode)

// 2) استدعاء كميثود
const user = { name: "سارة", whoAmI };
user.whoAmI();                  // الكائن user نفسه

// 3) استدعاء صريح بـ call
whoAmI.call({ name: "ليلى" });  // { name: "ليلى" }

// 4) استدعاء بـ new
function Person(name) {
  this.name = name;
}
const p = new Person("كريم");   // this كائن جديد، و p.name === "كريم"

لو اتلخبطت بين قاعدتين، فيه ترتيب أولوية واضح: new بيكسب على bind، وbind بيكسب على استدعاء الميثود، واستدعاء الميثود بيكسب على الاستدعاء الحر. والدالة السهمية حالة خاصة بتتجاهل القواعد دي كلها، وهي اللي جاية دلوقتي.

الدوال السهمية: الحل اللي بيقفل أغلب الوجع

الدالة السهمية (=>) مالهاش this خاص بيها أصلاً. لمّا تكتب this جوّاها، هي بتاخدها من المكان اللي اتعرّفت فيه، يعني من الدالة الأب أو الـ scope المحيط. ودي قيمة ثابتة: مفيش call ولا bind يقدر يغيّرها. ده اللي بيخلّيها الحل العملي لأغلب مشاكل this.

المثال الكلاسيكي: عدّاد بيزوّد رقم كل ثانية. النسخة المكسورة الأول:

JavaScript
const counter = {
  count: 0,
  start() {
    // this هنا = counter  (استدعاء كميثود)
    setInterval(function () {
      // دالة عادية اتنادت بشكل حر جوّه setInterval
      // this هنا = undefined  ->  الكراش
      this.count++;
    }, 1000);
  },
};

counter.start();  // TypeError: Cannot read properties of undefined

دلوقتي نفس الكود بدالة سهمية:

JavaScript
const counter = {
  count: 0,
  start() {
    setInterval(() => {
      // الدالة السهمية ورّثت this من start()
      // يعني this = counter  زي ما احنا عايزين
      this.count++;
      console.log(this.count);
    }, 1000);
  },
};

counter.start();  // 1, 2, 3, ...

الفرق سطر واحد: function () {} بقت () => {}. الدالة العادية اتنادت بشكل حر فخسرت الكائن؛ الدالة السهمية مالهاش this خاص فورّثت this بتاع start.

سيناريو واقعي: زرار دفع بيبعت الطلب مرتين

خد حالة فعلية. عندك صفحة دفع فيها class بيمثّل زرار التأكيد، وميثود handleClick بيعمل this.disabled = true عشان يمنع الضغط مرتين. الكود بيشتغل تمام لمّا تستدعيه يدوي. بس انت ربطته بالحدث كده: button.addEventListener("click", obj.handleClick).

هنا حصلت الكارثة بهدوء. addEventListener بيستدعي الدالة بشكل حر، فـ this بقت مش الكائن. السطر this.disabled = true فشل في صمت، الزرار فضل شغّال، والمستخدم اللي بيدوس مرتين بيبعت الطلب مرتين. في موقع بـ 12 ألف عملية دفع في اليوم، نسبة دوسة مزدوجة 0.8% معناها حوالي 96 طلب مكرر يوميًا لازم يترجّع يدوي. الحل سطر واحد: تبعت obj.handleClick.bind(obj)، أو تعرّف handleClick كـ class field سهمي عشان يفضل مربوط بالكائن مهما اتنقل.

الـ trade-offs اللي محدش بيقولك عليها

كل حل من دول له ثمن. متختارش واحد على عماك.

  • الـ class field السهمي (handleClick = () => {...}) بيحل this تمامًا، لكن بيعمل نسخة من الدالة لكل instance بدل ما تتشارك على الـ prototype. لو بتعمل 10 آلاف instance، ده 10 آلاف نسخة دالة في الذاكرة. مع كائنات قليلة مفيش فرق محسوس؛ مع كائنات كتير جدًا الموضوع بيبان.
  • .bind() بيرجّع دالة جديدة كل مرة بتناديه. لو ناديته جوّه دالة الرسم في React، انت بتعمل reference جديدة كل render، واللي بيكسر React.memo ويخلّي الكومبوننت الابن يعيد الرسم بدون لزمة. اعمل الـ bind مرة واحدة بره مسار الرسم.
  • الدالة السهمية ثابتة الـ this، يعني مينفعش تستخدمها لمّا تكون فعلاً محتاج this ديناميكية، زي ميثود على prototype مفروض يشتغل على أي كائن يناديه. وكمان مينفعش تستخدمها مع new.
  • الوضع الصارم strict mode بيخلّي this في الاستدعاء الحر undefined بدل window. ده مكسب: بيوقّعك بـ error واضح بدل ما يكتب على الكائن العام في صمت. بس لو عندك كود قديم بيعتمد على السلوك القديم، هيتكسر.

متى لا تشغّل بالك بالموضوع ده

مش كل كود محتاج تفكّر في this.

  • لو بتكتب modules بدوال نقية بتاخد كل حاجة كـ arguments وبترجّع قيمة، this مش بتلمسك أصلاً.
  • React بالـ hooks شالت this تقريبًا من كود الكومبوننت؛ لو مشروعك function components بس، الموضوع بيخصّك أقل بكتير.
  • لو كل ميثوداتك بتتنادى دايمًا بصيغة obj.method() وعمرها ما بتتنقل كـ callback، القاعدة التانية كفاية ومش محتاج تعقّد.

الافتراض هنا إنك شغّال على JavaScript حديثة (ES2015 وأحدث) بـ strict mode مفعّل، وده الوضع الافتراضي جوّه أي module أو class.

المصادر

  • MDN Web Docs — صفحة this وصفحة Arrow function expressions.
  • ECMAScript Language Specification (ECMA-262) — قسم Execution Contexts و this binding.
  • MDN Web Docs — Function.prototype.bind() وFunction.prototype.call().
  • Kyle Simpson — كتاب «You Don't Know JS Yet: this & Object Prototypes».

الخطوة التالية

دلوقتي افتح أقدم ملف فيه class في مشروعك. دوّر على أي ميثود بيتبعت كـ callback لـ addEventListener أو setTimeout أو .map. لكل واحدة اسأل سؤال واحد: لو الدالة دي اتنادت لوحدها، this هتبقى إيه؟ لو الإجابة «undefined وأنا محتاجها الكائن»، حوّلها لدالة سهمية أو ضيف .bind(this) في مكان التعريف. ابدأ بملف واحد النهاردة، وشغّل الاختبارات بعدها؛ لو عدّت، انت قفلت فئة كاملة من الـ bugs الصامتة.

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة