تعمل هذه الكلمة الرئيسية

تشير الكلمة الرئيسية this إلى قيمة العنصر المرتبط بالدالة في وقت استدعائها، ما يعني أنّ قيمتها تختلف استنادًا إلى ما إذا كان يتم استدعاء الدالة كطريقة أو دالة مستقلة أو مُنشئ.

عند استدعاء دالة، يتم إنشاء مثيل للكلمة الرئيسية this بدون إعلامك كإشارة إلى العنصر الذي يحتوي على هذه الدالة، ما يتيح لك الوصول إلى السمات والطُرق المحدّدة بجانبها من داخل نطاقها. يشبه العمل مع this في بعض النواحي العمل مع متغيّر تمّت تعريفه باستخدام const. مثل الثابت، لا يمكن إزالة this ولا يمكن إعادة تعيينه، ولكن يمكن تغيير طرق الكائن الذي تحتوي عليه الكلمة الرئيسيةthis.

الربط العام

خارج الدالة أو سياق كائن، يشير الرمز this إلى سمة globalThis، وهي إشارة إلى الكائن العام في معظم بيئات JavaScript. في سياق نص برمجي يتم تشغيله في متصفّح ويب، الكائن العام هو كائن window:

this;
> Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, ...}

في Node.js، globalThis هو عنصر global:

$ node
Welcome to Node.js v20.10.0.
Type ".help" for more information.
> this
<ref *1> Object [global] {
...
}

خارج الوضع الصارم، يشير this أيضًا إلى الكائن العام داخل دالة مستقلة، لأنّ العنصر الرئيسي Window هو الكائن الذي "يملك" هذه الدوال بشكل فعّال.

function myFunction() {
    console.log( this );
}
myFunction();
> Window {...}

(function() {
    console.log( this );
}());
> Window {...}

عند استخدام الوضع الصارم، تكون قيمة this هي undefined داخل دالة مستقلة:

(function() {
    "use strict";
    console.log( this );
}());
> undefined

قبل طرح الوضع الصارم، كان يتم استبدال قيمة null أو undefined لعنصر this بمرجع إلى العنصر الشامل. قد ترى أحيانًا الربط الشامل يُشار إليه باسم "الربط التلقائي" بسبب هذا السلوك القديم.

الربط الضمني

عند استدعاء دالة كطريقة لكائن، يشير مثيل this داخل هذه الطريقة إلى الكائن الذي يحتوي على الطريقة، ما يتيح الوصول إلى methods والسمات التي تصاحبها:

let myObject = {
    myValue: "This is my string.",
    myMethod() {
            console.log( this.myValue );
    }
};

myObject.myMethod();
> "This is my string."

قد يبدو أنّ قيمة this تعتمد على كيفية تعريف الدالة والعنصر المُحيط بها. بدلاً من ذلك، يكون سياق قيمة this هو سياق التنفيذ الحالي. في هذه الحالة، يكون سياق التنفيذ هو أنّ كائن myObject يستدعي الطريقة myMethod، وبالتالي يكون myObject هو القيمة لـ this. قد يبدو هذا الأمر تقنيًا في سياق المثالين السابقين، ولكن بالنسبة إلى الاستخدامات الأكثر تقدمًا لـ this، من المهم مراعاة هذا الاختلاف.

بشكل عام، استخدِم this بطرق لا تتوقع أن يكون للرمز المحيط بها أي بنية معيّنة. الاستثناء من هذه القاعدة هو ES5 دوالّ الأسهم.

this في دوال الأسهم

في الدوالّ السهمية، يتم تحليلthis إلى عملية ربط في بيئة تشمل السياق. وهذا يعني أنّه this في دالة السهم تشير إلى قيمة this في السياق المحيط الأقرب لهذه الدالة:

let myObject = {
    myMethod() { console.log( this ); },
    myArrowFunction: () => console.log( this ),
    myEnclosingMethod: function () {
        this.myArrowFunction = () => { console.log(this) };
    }
};

myObject.myMethod();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }

myObject.myArrowFunction();
> Window {...}

في المثال السابق، يسجِّل myObject.myMethod() العنصر myObject كجسم "يملك" هذه الطريقة، ولكن myObject.myArrowFunction() تعرِض globalThis (أو undefined)، لأنّ مثيل this داخل دالة السهم يشير بدلاً من ذلك إلى النطاق المحيط الأعلى.

في المثال التالي، تنشئ myEnclosingMethod دالة سهم على العنصر الذي يحتوي عليها عند تنفيذها. تشير الآن نسخة this داخل دالة السهم إلى قيمة this داخل السياق المغلق ، وهو الطريقة التي تحتوي على دالة السهم هذه. بما أنّ قيمة this داخل myEnclosingMethod تشير إلى myObject، بعد تحديد دالة السهم، تشير this داخل دالة السهم أيضًا إلى myObject:

let myObject = {
    myMethod() { console.log( this ); },
    myEnclosingMethod: function () {
        this.myArrowFunction = () => { console.log(this) };
    }
};

myObject.myEnclosingMethod();
myObject.myArrowFunction();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }

الربط الصريح

يعالج الربط الضمني معظم حالات الاستخدام للعمل مع this. ومع ذلك، قد تحتاج أحيانًا إلى قيمة this لتمثيل سياق تنفيذ محدّد، بدلاً من السياق المُفترَض. أحد الأمثلة التوضيحية، وإن كان قديمًا بعض الشيء، هو استخدام this ضمن دالة ردّ الاتصال الخاصة بـ setTimeout، لأنّ دالة ردّ الاتصال هذه لها سياق تنفيذ فريد:

var myObject = {
  myString: "This is my string.",
  myMethod() {
    console.log( this.myString );
  }
};
myObject.myMethod();
> "This is my string."

setTimeout( myObject.myMethod, 100 );
> undefined

على الرغم من أنّه تمّ حلّ هذا النقص المحدّد في setTimeout من خلال ميزات أخرى، تمّ حلّ مشاكل مشابهة "لفقدان" this في السابق من خلال إنشاء إشارة صريحة إلى قيمة this ضمن نطاق السياق المقصود. قد ترى أحيانًا حالات يتم فيها منح this لمتغيّر باستخدام معرّفات مثل that أو self أو _this في قواعد برمجية قديمة. هذه هي اصطلاحات المعرّفات الشائعة للمتغيّرات التي تحتوي على قيمة this مُرسَلة.

عند استدعاء دالة باستخدام الطريقتَين call() أو bind() أو apply()، this تشير صراحةً إلى الكائن الذي يتم استدعاؤه:

let myFunction = function() {
    console.log( this.myValue );
}

let myObject = {
   "myValue" : "This is my string."
 };

myFunction.call( myObject );
> "This is my string."
var myObject = {
  myString: "This is my string.",
  myMethod() {
    console.log( this.myString );
  }
};

setTimeout( myObject.myMethod.bind( myObject ), 100 );
> "This is my string."

تلغي عملية الربط الصريح قيمة this المقدَّمة من عملية الربط الضمني.

let myObject = {
    "myValue" : "This string sits alongside myMethod.",
    myMethod() {
        console.log( this.myValue );
    }
};
let myOtherObject = {
    "myValue" : "This is a string in another object entirely.",
};

myObject.myMethod.call( myOtherObject );
> "This is a string in another object entirely."

إذا تمّ استدعاء دالة بطريقة تؤدي إلى ضبط قيمة this على undefined أو null، يتم استبدال هذه القيمة بglobalThis خارج الوضع الصارم:

let myFunction = function() {
    console.log( this );
}

myFunction.call( null );
> Window {...}

وبالمثل، إذا تمّ استدعاء دالة بطريقة تمنح this قيمة أساسية ، يتمّ استبدال هذه القيمة بعنصر التفاف القيمة الأساسية خارج الوضع الصارم:

let myFunction = function() {
    console.log( this );
}

let myNumber = 10;

myFunction.call( myNumber );
> Number { 10 }

في الوضع الصارم، لا يتم تحويل قيمة this المرسَلة إلى عنصر بأي شكل من الأشكال، حتى إذا كانت قيمة أساسية أو null أو undefined:

"use strict";
let myFunction = function() {
    console.log( this );
}

let myNumber = 10;

myFunction.call( myNumber );
> 10

myFunction.call( null );
> null

new ربط

عند استخدام فئة كمنشئ باستخدام الكلمة الرئيسية new، يشير this إلى المثيل الذي تم إنشاؤه حديثًا:

class MyClass {
    myString;
    constructor() {
        this.myString = "My string.";
    }
    logThis() {
        console.log( this );
    }
}
const thisClass = new MyClass();

thisClass.logThis();
> Object { myString: "My string." }

وبالمثل، تشير قيمة this داخل دالة باني يتم استدعاؤها باستخدام new إلى العنصر الذي يتم إنشاؤه:

function MyFunction() {
  this.myString = "My string.";
  this.logThis = function() {
    console.log( this );
  }
}
const myObject = new MyFunction();

myObject.logThis();
> Object { myString: "My string.", logThis: logThis() }

ربط معالج الحدث

في سياق معالجات الأحداث، تشير قيمة this إلى العنصر الذي يُستخدَم لتشغيلها. داخل دالة ردّ الاتصال لمعالج الأحداث، يعني ذلك أنّ this يشير إلى العنصر المرتبط بالمعالج:

let button = document.querySelector( "button" );

button.addEventListener( "click", function( event ) { console.log( this ); } );

عندما يتفاعل مستخدم مع button في المقتطف السابق، تكون النتيجة هو عنصر العنصر الذي يحتوي على <button> نفسه:

> Button {}

عند استخدام دالة سهم كدالّة ردّ اتصال لمُستمع الأحداث، يتمّ توفير قيمة this مرة أخرى من خلال أقرب سياق تنفيذ مُغلق. في المستوى العلوي، يعني ذلك أنّ this داخل دالة ردّ اتصال معالِج الحدث هو globalThis:

let button = document.querySelector( "button" );

button.addEventListener( "click", ( event ) => { console.log( this ); } );
> undefined

كما هو الحال مع أي عنصر آخر، عند استخدام الطريقة call() أو bind() أو apply() للإشارة إلى دالة ردّ الاتصال الخاصة بمراقب الحدث، تشير this إلى العنصر صراحةً:

let button = document.querySelector( "button" );
let myObject = {
    "myValue" : true
};
function handleClick() {
    console.log( this );
}

button.addEventListener( "click", handleClick.bind( myObject ) );
> Object { myValue: true }

التحقّق من فهمك

بالنسبة إلى نص برمجي يتم تشغيله في متصفّح ويب، ما هو العنصر الشامل الذي يشير إليه this عند استخدامه خارج دالة أو سياق عنصر؟

عنصر window
عنصر browser
عنصر undefined