المقدمة

في هذه المقالة سنتكلم عن  This  keyword في JavaScript وهي تعتبر واحدة من أكثر المفاهيم اللى بتلخبط المبرمجين ودا لأن قيمتها تتغير على حسب السياق اللي الكود بيتنفذ فيه وازاي تم كتابة الـ function الموجودة فيها.


دور This

تحمل This قيمة ال object المسئول عن تنفيذ الكود أو الذي قام باستدعاء الدالة.

💡
ملحوظة مهمة: قيمة this بتختلف في strict mode , non-strict mode.. ففي non-strict mode دائما هناك قيمة ل this أما في strict mode يمكن أن تحتوي على قيمة أو تكون undefined إذا كان هناك اختلاف سيتم ذكره في الأمثلة إن شاء الله.

Global Context (window)

أولاً استخدام this في ال global context = window هنلاقي في المثال الأول تم تنفيذ الكود في الـ global لذلك هتكون قيمة this بتساوي ال window object


//example 1
console.log(this); //{window: Window, self: Window, document: document, name: '', location: Location, ...}
window.x = "x";
console.log(this.x); // "x"

Method

أما استخدام this في سياق الـ Functions هنلاقي قيمتها بتتغير على حسب كيفية استدعاء الـ Function.

// example 2
const obj = {
  a: "a",
  method: function () {
    console.log(this);
  },
};
obj.method(); // output=>  {a: 'a', method: ƒ}

هنلاقي في المثال ده اللي عمل استدعاء للـ Function هو obj هتكون قيمة this هي ال obj


ملحوظة مهمة: قيمة this بتتحدد عند استدعاء الـ Function. كما موضح في المثال الثالث

//
example 3
const obj1 = {
  a: "one",
  method: function () {
    console.log(this);
  },
};
const obj2 = {
  a: "two",
};
obj2.method = obj1.method;

obj1.method(); // output=>  {a: 'one', method: ƒ}
obj2.method(); // output=>  {a: 'two', method: ƒ

هنلاقي هنا this قيمتها اتغيرت على حسب مين عمل استدعاء لها.


Regular Function

عند استخدام This في regular function هنلاقي إن دائما قيمتها بتكون الـ window object بغض النظر عن السياق اللي تم تنفيذ الكود فيه كما في المثال الرابع


//
example 4
"use strict";
const regularFunc = function () {
  console.log(this);
};
regularFunc(); // output=> Window {window: Window, self: Window, document: document, name: '', location: Location, …}

هنلاقي قيمة this وده لأنه يعتبر اللي استدعى الدالة هو الـ window object.

و زي ماقولنا إن قيمتها بتكون window object بغض النظر عن السياق في المثال الخامس هنوضح الكلام ده.

// example 5
const obj = {
  a: "one",
  method: function () {
    console.log(this);
    return function () {
      console.log(this);
    };
  },
};
obj.method(); // output=> {a: 'one', method: ƒ}
obj.method()(); // output=> Window {window: Window, self: Window, document: document, name: '', location: Location

هنلاقي قيمة this الأولي بتشير لـ obj لانها اللي استدعت ال method ولكن الثانية تم تنفيذها بداخل regular function لذلك هتكون قيمتها window obj بغض النظر عن مين استدعاها.

💡
ملحوظة مهمة: الأمثلة اللي فاتت في ال regular كانت في non-strict mode لكن في strict mode هتكون قيمتها undefined كما هو موضح في المثال السادس.
example 6
"use strict";
const regularFunc = function () {
  console.log(this);
};
regularFunc(); // output => undefined

const obj = {
  a: "one",
  method: function () {
    console.log(this); // output => {a: 'one', method: ƒ}
    return function () {
      console.log(this); // output => undefined
    };
  },
};
obj.method(); // output=> {a: 'one', method: ƒ}
obj.method()(); // undefined

لو فكرنا هنا هنلاقي إن أي this كانت قيمتها window في ال strict mode هتكون قيمتها undefined وده منطقي لان القاعدة بتقول إن this بتشيل قيمة ال object اللي عملها call هنلاقي في المثال السادس إن ()regularFunc  مفيش obj عملتلها call.


Arrow Function

مفهوم this في ال Arrow function مختلف شوية في الدالة العادية قيمة this بتتحدد وقت استدعاء الدالة وبتعتمد مين اللي عملها استدعاء لكن في ال Arrow function ملهاش قيمة لذلك هي بتاخد قيمة الـ parent scope اللي تم تعريفها فيه كما في المثال السابع 


//example 7
const a = {
  a: "a",

  arrFunc: () => {
    console.log(this);
  },
};
a.arrFunc(); // output=> Window {window: Window, self: Window, document: document, name: '', location: Location, …}

نلاقي قيمة this هي الـ parent scope وفي هذه الحالة هو الـ window object.

ملحوظة : ممكن تفكر إن {...}=const a  لها ال scope الخاص بها ولكن هذا غير صحيح لأنه object literal وليس code block أي إنه مجرد طريقة لتعريف الـ object a لذلك ال parent scope لــ ()arrFunc هو الـ window

و لتوضيح المعلومة أكثر هنشوف المثال الثامن

example 8
const obj = {
  a: "a",

  method: function () {
    const innerFunc = () => console.log(this);
    innerFunc();
  },
};
obj.method(); // output=>{a: 'a', method: ƒ

هنلاقي هنا this أخذت قيمتها من الـ parent scope اللي تم تعريفها فيه واللي في هذه الحالة هو ال method function لذلك قيمتها هتبقي ال obj اللي تم استدعاؤها فيه.


في الختام

استخدام This ككلمة مفتاحية أثناء كتابتنا للكود باستخدام JS لا غنى عنه ووضحنا في هذا المقال كل الطرق اللي نقدر نستخدمها بيها وقيمتها في كل حالة, إلى اللقاء في مقال قادم 👋