تشير الكلمة الرئيسية 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