شرح JavaScript `هذه` Keyword + 5 قواعد ربط أساسية للمبتدئين في JS

تعد thisالكلمات الرئيسية لجافا سكريبت من أصعب جوانب اللغة للفهم. لكنها مهمة للغاية لكتابة كود JavaScript أكثر تقدمًا.

في JavaScript ، thisتتيح لنا الكلمة الأساسية:

  • إعادة استخدام الوظائف في سياقات مختلفة ، و
  • حدد الكائن الذي يجب التركيز عليه عند استدعاء الطريقة.

عندما يتعلق الأمر this، فإن السؤال المهم الذي يجب طرحه هو أين يتم استدعاء الوظيفة. لأننا لا نعرف ما هو موجود في thisالكلمة الأساسية حتى يتم استدعاء الوظيفة.

استخدام thisيمكن تصنيفها إلى خمسة مختلف bindingالجوانب. في هذه المقالة ، سوف نتعرف على جميع الجوانب الخمسة مع أمثلة.

أولا ، ما هو ملزم؟

في JavaScript ، Lexical Environmentيتم كتابة التعليمات البرمجية الخاصة بك فعليًا. في المثال أدناه ، اسم المتغير موجود lexicallyداخل الوظيفة sayName().

function sayName() { let name = 'someName'; console.log('The name is, ', name); }

و Execution Contextيشير إلى التعليمات البرمجية التي يتم تشغيلها حاليا وشيء آخر أن يساعد تشغيله. يمكن أن يكون هناك الكثير من البيئات المعجمية المتاحة ولكن البيئة التي تعمل حاليًا تتم إدارتها بواسطة سياق التنفيذ .

يحتوي كل سياق تنفيذ على ملحق Environment Record. Bindingفي JavaScript يعني تسجيل المعرف (المتغير واسم الوظيفة) في سجل بيئة معين.

ملاحظة: Bindingتساعد في ربط المعرف (المتغير واسم الوظيفة) thisبالكلمة الأساسية لملف execution context.

لا تقلق إذا وجدت صعوبة في فهم ذلك الآن. سوف تحصل على فهم أفضل بينما نمضي قدمًا.

القاعدة رقم 1: كيف يعمل الربط الضمني لجافا سكريبت

يغطي الربط الضمني معظم حالات الاستخدام للتعامل مع thisالكلمة الأساسية.

في الربط الضمني ، تحتاج إلى التحقق مما هو على يسار عامل النقطة (.) المجاور للدالة في وقت الاستدعاء. هذا يحدد ما thisهو ملزم.

دعونا نلقي نظرة على مثال لفهمه بشكل أفضل.

let user = { name: 'Tapas', address: 'freecodecamp', getName: function() { console.log(this.name); } }; user.getName();

هنا thisمرتبط بكائن المستخدم. نحن نعلم هذا لأننا getName()نرى userالكائن على يسار عامل النقطة (.) المجاور للدالة . لذلك this.nameسوف نقوم بتسجيل Tapas في وحدة التحكم.

دعونا نرى مثالًا آخر لفهم هذا المفهوم بشكل أفضل:

function decorateLogName(obj) { obj.logName = function() { console.log(this.name); } }; let tom = { name: 'Tom', age: 7 }; let jerry = { name: 'jerry', age: 3 }; decorateLogName(tom); decorateLogName(jerry); tom.logName(); jerry.logName();

في هذا المثال ، لدينا كائنان ، tomو jerry. لقد قمنا بتزيين (تحسين) هذه الكائنات من خلال إرفاق طريقة تسمى logName().

لاحظ أنه عند الاستدعاء tom.logName()، يكون tomالكائن على يسار عامل النقطة (.) المجاور للدالة logName(). لذلك thisفهو مرتبط tomبالكائن ويسجل القيمة tom ( this.nameيساوي tom هنا). الأمر نفسه ينطبق عند jerry.logName()الاحتجاج.

القاعدة رقم 2: كيف يعمل JavaScript Explicit Binding

لقد رأينا أن JavaScript ينشئ بيئة لتنفيذ الكود الذي نكتبه. يهتم بإنشاء الذاكرة للمتغيرات والوظائف والكائنات وما إلى ذلك في مرحلة الإنشاء . أخيرًا ينفذ الكود في مرحلة التنفيذ . هذه البيئة الخاصة تسمى Execution Context.

يمكن أن يكون هناك العديد من هذه البيئات (سياقات التنفيذ) في تطبيق JavaScript. يعمل كل سياق تنفيذي بشكل مستقل عن الآخرين.

لكن في بعض الأحيان ، قد نرغب في استخدام أشياء من سياق تنفيذ في آخر. هذا هو المكان الذي يلعب فيه الارتباط الصريح.

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

هناك ثلاث طرق خاصة جدا، call()، apply()و bind()التي تساعدنا على تحقيق ملزمة صريحة.

كيف call()تعمل طريقة JavaScript

باستخدام call()الطريقة ، سيتم تمرير السياق الذي يجب استدعاء الوظيفة به كمعامل إلى call(). دعونا نرى كيف يعمل مع مثال:

let getName = function() { console.log(this.name); } let user = { name: 'Tapas', address: 'Freecodecamp' }; getName.call(user);

هنا call()يتم استدعاء الطريقة على وظيفة تسمى getName(). و getName()ظيفة يسجل فقط this.name. لكن ما هو thisهنا؟ يتم تحديد ذلك من خلال ما تم تمريره إلى call()الطريقة.

هنا ، thisسيتم الارتباط بكائن المستخدم لأننا قد مررنا المستخدم كمعامل إلى call()الطريقة. لذلك this.nameيجب تسجيل قيمة خاصية اسم كائن المستخدم ، أي Tapas .

في المثال أعلاه ، مررنا حجة واحدة فقط إلى call(). ولكن يمكننا أيضًا تمرير عدة حجج إلى call()، مثل هذا:

let getName = function(hobby1, hobby2) { console.log(this.name + ' likes ' + hobby1 + ' , ' + hobby2); } let user = { name: 'Tapas', address: 'Bangalore' }; let hobbies = ['Swimming', 'Blogging']; getName.call(user, hobbies[0], hobbies[1]);

لقد مررنا هنا عدة حجج call()للطريقة. يجب أن تكون الوسيطة الأولى هي سياق الكائن الذي يجب من خلاله استدعاء الوظيفة. يمكن أن تكون المعلمات الأخرى مجرد قيم لاستخدامها.

أنا هنا يمر سباحة و التدوين عن اثنين من المعلمات إلى getName()وظيفة.

هل لاحظت نقطة ألم هنا؟ في حالة أ call()، يجب تمرير الحجج واحدة تلو الأخرى - وهي ليست طريقة ذكية للقيام بالأشياء! وهنا يأتي دور طريقتنا التالية apply()في الصورة.

كيف apply()تعمل طريقة JavaScript

call()يمكن حل هذه الطريقة المحمومة لتمرير الحجج إلى الطريقة بواسطة طريقة بديلة أخرى تسمى apply(). إنه بالضبط نفس الشيء call()ولكنه يسمح لك بتمرير الحجج بشكل أكثر ملاءمة. الق نظرة:

let getName = function(hobby1, hobby2) { console.log(this.name + ' likes ' + hobby1 + ' , ' + hobby2); } let user = { name: 'Tapas', address: 'Bangalore' }; let hobbies = ['Swimming', 'Blogging']; getName.apply(user, hobbies);

نحن هنا قادرون على تمرير مجموعة من الحجج ، وهو أمر أكثر ملاءمة من تمريرها واحدة تلو الأخرى.

تلميح: عندما يكون لديك وسيط قيمه واحده فقط أو لا توجد وسيطات قيمه لتمريرها ، استخدم call(). عندما يكون لديك عدة وسيطات قيمة لتمريرها ، استخدم apply().

كيف bind()تعمل طريقة JavaScript

و bind()الطريقة مشابهة ل call()طريقة ولكن مع فارق واحد. على عكس call()طريقة استدعاء الوظيفة مباشرة ، يتم bind()إرجاع دالة جديدة تمامًا ويمكننا استدعاءها بدلاً من ذلك.

let getName = function(hobby1, hobby2) { console.log(this.name + ' likes ' + hobby1 + ' , ' + hobby2); } let user = { name: 'Tapas', address: 'Bangalore' }; let hobbies = ['Swimming', 'Blogging']; let newFn = getName.bind(user, hobbies[0], hobbies[1]); newFn();

Here the getName.bind() doesn't invoke the function getName()directly. It returns a new function, newFn and we can invoke it as newFn().

Rule #3: The JavaScript new Binding

A new keyword is used to create an object from the constructor function.

let Cartoon = function(name, animal) { this.name = name; this.animal = animal; this.log = function() { console.log(this.name + ' is a ' + this.animal); } };

You can create objects using the new keyword  like this:

 let tom = new Cartoon('Tom', 'Cat'); let jerry = new Cartoon('Jerry', 'Mouse');

The constructor function's new binding rule states that, when a function is invoked with the new keyword, the this keyword inside the function binds to the new object being constructed.

Sounds complex? Ok, let's break it down. Take this line,

let tom = new Cartoon('Tom', 'Cat');

Here the function Cartoon is invoked with the new keyword. So this will be bound to the new object being created here, which is tom.

Rule #4: JavaScript Global Object Binding

What do you think will be the output of the code below? What is this binding to here?

let sayName = function(name) { console.log(this.name); }; window.name = 'Tapas'; sayName();

If the this keyword is not resolved with any of the bindings, implicit, explicit or new, then the this is bound to the window(global) object.

There is one exception though. JavaScript strict mode does not allow this default binding.

"use strict"; function myFunction() { return this; }

In the above case, this is undefined.

Rule #5: HTML Event Element Binding in JavaScript

In HTML event handlers, this binds to the HTML elements that receive the event.

Click Me!

The is the output log in the console when you click on the button:

"Click Me!"

You can change the button style using the this keyword, like this:

Click Me!

But be mindful when you call a function on the button click and use this inside that function.

Click Me!

and the JavaScript:

function changeColor() { this.style.color='teal'; }

The above code won't work as expected. As we have seen in the Rule 4, here this will be bound to the global object (in the 'non-strict' mode) where there is no style object to set the color.

In Summary

To summarize,

  • In the case of implicit binding, this binds to the object to the left of the dot(.) operator.
  • In the case of explicit binding, we can call a function with an object when the function is outside of the execution context of the object. The methods call(), apply(), and bind() play a big role here.
  • When a function is invoked with the new keyword, the this keyword inside the function binds to the new object being constructed.
  • When the this keyword is not resolved with any of the bindings, implicit, explicit or new, then this is bound to the window(global) object. In JavaScript's strict mode, this will be undefined.
  • In HTML event handlers, this binds to the HTML elements that receive the event.

There is one more case where this behaves differently, such as with ES6 arrow functions. We will take a look at that in a future article.

I hope you found this article insightful. You may also like,

  • JavaScript Hoisting Internals
  • Understanding JavaScript Execution Context like never before
  • JavaScript Scope Fundamentals with Tom and Jerry
  • Understanding JavaScript Closure with example

إذا كانت هذه المقالة مفيدة ، فيرجى مشاركتها حتى يتمكن الآخرون من قراءتها أيضًا. يمكنك @ me على Twitter (tapasadhikary) مع التعليقات ، أو لا تتردد في متابعتي.